diff --git a/Cargo.lock b/Cargo.lock index 4461038ad4..89fa577626 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4180,7 +4180,7 @@ dependencies = [ [[package]] name = "fudge" version = "0.0.10" -source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#c6ee97cc74d023a891fd6029d8f4bd3f67d4fbe2" +source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#a7162cac11809579ff23f74628a70700075e6a14" dependencies = [ "fudge-companion", "fudge-core", @@ -4193,7 +4193,7 @@ dependencies = [ [[package]] name = "fudge-companion" version = "0.0.7" -source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#c6ee97cc74d023a891fd6029d8f4bd3f67d4fbe2" +source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#a7162cac11809579ff23f74628a70700075e6a14" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4204,7 +4204,7 @@ dependencies = [ [[package]] name = "fudge-core" version = "0.0.10" -source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#c6ee97cc74d023a891fd6029d8f4bd3f67d4fbe2" +source = "git+https://github.com/centrifuge/fudge?branch=polkadot-v0.9.43#a7162cac11809579ff23f74628a70700075e6a14" dependencies = [ "async-trait", "bitvec 1.0.1", @@ -11464,6 +11464,7 @@ dependencies = [ "pallet-authorship", "pallet-babe", "pallet-balances", + "pallet-beefy", "pallet-block-rewards", "pallet-collator-selection", "pallet-collective", @@ -11513,6 +11514,7 @@ dependencies = [ "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", + "sp-consensus-beefy", "sp-consensus-slots", "sp-core", "sp-inherents", @@ -11527,7 +11529,6 @@ dependencies = [ "tracing-subscriber", "xcm", "xcm-executor", - "xcm-simulator", ] [[package]] @@ -16511,24 +16512,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "xcm-simulator" -version = "0.9.43" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.43#ba42b9ce51d25bdaf52d2c61e0763a6e3da50d25" -dependencies = [ - "frame-support", - "parity-scale-codec 3.6.5", - "paste", - "polkadot-core-primitives", - "polkadot-parachain", - "polkadot-runtime-parachains", - "sp-io", - "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", -] - [[package]] name = "yamux" version = "0.10.2" diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index cb3a76d983..7fd20d7122 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -90,9 +90,6 @@ orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-li orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } -# Misc -xcm-simulator = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43" } - # Local altair-runtime = { path = "../altair" } centrifuge-runtime = { path = "../centrifuge" } diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index c8f0bcb92a..49dd7c082b 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -39,9 +39,73 @@ use crate::{ mod utils { use super::*; - pub(crate) fn parachain_account(id: u32) -> AccountId { + pub fn parachain_account(id: u32) -> AccountId { polkadot_parachain::primitives::Sibling::from(id).into_account_truncating() } + + pub fn xcm_metadata(transferability: CrossChainTransferability) -> Option { + match transferability { + CrossChainTransferability::Xcm(x) | CrossChainTransferability::All(x) => Some(x), + _ => None, + } + } + + 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 parachain. + 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)); + } } type FudgeRelayRuntime = <::FudgeHandle as FudgeHandle>::RelayRuntime; @@ -58,63 +122,6 @@ mod altair { 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, @@ -231,13 +238,6 @@ mod altair { // 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::*; @@ -740,11 +740,6 @@ mod altair { 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) - ); }); } @@ -1283,3 +1278,1237 @@ mod altair { crate::test_for_runtimes!([altair], convert_unsupported_currency); } } + +mod centrifuge { + use centrifuge_runtime::{CurrencyIdConvert, PoolPalletIndex}; + + use super::*; + + mod utils { + use super::*; + + /// The test asset id attributed to DOT + pub const DOT_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(91); + + /// An Asset that is NOT XCM transferable + pub const NO_XCM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(401); + + /// Register DOT in the asset registry. + /// It should be executed within an externalities environment. + pub fn register_dot() { + let meta: AssetMetadata = AssetMetadata { + decimals: 10, + name: "Polkadot".into(), + symbol: "DOT".into(), + existential_deposit: 100_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::parent())), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(DOT_ASSET_ID) + )); + } + + /// Register AUSD in the asset registry. + /// It should be executed within an externalities environment. + pub fn register_ausd() { + 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::polkadot::acala::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) + )); + } + + /// Register CFG in the asset registry. + /// It should be executed within an externalities environment. + pub fn register_cfg() { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Centrifuge".into(), + symbol: "CFG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + general_key(parachains::polkadot::centrifuge::CFG_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::Native) + )); + } + + /// Register CFG in the asset registry as XCM v2, just like it is in + /// production. It should be executed within an externalities + /// environment. + pub fn register_cfg_v2() { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Centrifuge".into(), + symbol: "CFG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V2(xcm::v2::MultiLocation::new( + 1, + xcm::v2::Junctions::X2( + xcm::v2::Junction::Parachain(T::FudgeHandle::PARA_ID), + xcm::v2::Junction::GeneralKey( + WeakBoundedVec::>::force_from( + parachains::polkadot::centrifuge::CFG_KEY.into(), + None, + ), + ), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(CurrencyId::Native) + )); + } + + /// Register a token whose `CrossChainTransferability` does NOT include + /// XCM. + pub fn register_no_xcm_token() { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "NO XCM".into(), + symbol: "NXCM".into(), + existential_deposit: 1_000_000_000_000, + location: None, + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(NO_XCM_ASSET_ID) + )); + } + + pub fn cfg_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 DOT tokens + pub fn dot_fee() -> Balance { + fee(10) + } + + 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 cfg(amount: Balance) -> Balance { + amount * dollar(currency_decimals::NATIVE) + } + + pub fn dollar(decimals: u32) -> Balance { + 10u128.saturating_pow(decimals) + } + + pub fn ausd(amount: Balance) -> Balance { + amount * dollar(currency_decimals::AUSD) + } + + pub fn dot(amount: Balance) -> Balance { + amount * dollar(10) + } + + pub fn foreign(amount: Balance, decimals: u32) -> Balance { + amount * dollar(decimals) + } + } + + use utils::*; + + mod asset_registry { + use super::*; + + fn register_cfg_works() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Centrifuge".into(), + symbol: "CFG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 0, + X1(general_key(parachains::polkadot::centrifuge::CFG_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(parachains::polkadot::acala::ID), + general_key(parachains::polkadot::acala::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!([centrifuge], register_cfg_works); + crate::test_for_runtimes!([centrifuge], register_foreign_asset_works); + crate::test_for_runtimes!([centrifuge], register_tranche_asset_blocked); + } + + mod currency_id_convert { + use super::*; + + fn convert_cfg() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + assert_eq!(parachains::polkadot::centrifuge::CFG_KEY, &[0, 1]); + + env.parachain_state_mut(|| { + // The way CFG is represented relative within the Centrifuge runtime + let cfg_location_inner: MultiLocation = MultiLocation::new( + 0, + X1(general_key(parachains::polkadot::centrifuge::CFG_KEY)), + ); + + register_cfg::(); + + assert_eq!( + >::convert(cfg_location_inner), + Ok(CurrencyId::Native), + ); + + // The canonical way CFG is represented out in the wild + let cfg_location_canonical: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(parachains::polkadot::centrifuge::ID), + general_key(parachains::polkadot::centrifuge::CFG_KEY), + ), + ); + + assert_eq!( + >::convert(CurrencyId::Native), + Some(cfg_location_canonical) + ) + }); + } + + /// Verify that even with CFG registered in the AssetRegistry with a XCM + /// v2 MultiLocation, that `CurrencyIdConvert` can look it up given an + /// identical location in XCM v3. + fn convert_cfg_xcm_v2() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + assert_eq!(parachains::polkadot::centrifuge::CFG_KEY, &[0, 1]); + + env.parachain_state_mut(|| { + // Registered as xcm v2 + register_cfg_v2::(); + + // The way CFG is represented relative within the Centrifuge runtime in xcm v3 + let cfg_location_inner: MultiLocation = MultiLocation::new( + 0, + X1(general_key(parachains::polkadot::centrifuge::CFG_KEY)), + ); + + assert_eq!( + >::convert(cfg_location_inner), + Ok(CurrencyId::Native), + ); + + // The canonical way CFG is represented out in the wild + let cfg_location_canonical: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(parachains::polkadot::centrifuge::ID), + general_key(parachains::polkadot::centrifuge::CFG_KEY), + ), + ); + + assert_eq!( + >::convert(CurrencyId::Native), + Some(cfg_location_canonical) + ) + }); + } + + /// Verify that a registered token that is NOT XCM transferable is + /// filtered out by CurrencyIdConvert as expected. + fn convert_no_xcm_token() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + env.parachain_state_mut(|| { + register_no_xcm_token::(); + + assert_eq!( + >::convert(NO_XCM_ASSET_ID), + None + ) + }); + } + + fn convert_ausd() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + assert_eq!(parachains::polkadot::acala::AUSD_KEY, &[0, 1]); + + let ausd_location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(parachains::polkadot::acala::ID), + general_key(parachains::polkadot::acala::AUSD_KEY), + ), + ); + + env.parachain_state_mut(|| { + register_ausd::(); + + assert_eq!( + >::convert(ausd_location), + Ok(AUSD_CURRENCY_ID), + ); + + assert_eq!( + >::convert(AUSD_CURRENCY_ID), + Some(ausd_location) + ) + }); + } + + fn convert_dot() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + let dot_location: MultiLocation = MultiLocation::parent(); + + env.parachain_state_mut(|| { + register_dot::(); + + assert_eq!( + >::convert(dot_location), + Ok(DOT_ASSET_ID), + ); + + assert_eq!( + >::convert(DOT_ASSET_ID), + Some(dot_location) + ) + }); + } + + fn convert_unknown_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].as_ref()), + ), + ); + + 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!([centrifuge], convert_cfg); + crate::test_for_runtimes!([centrifuge], convert_cfg_xcm_v2); + crate::test_for_runtimes!([centrifuge], convert_no_xcm_token); + crate::test_for_runtimes!([centrifuge], convert_ausd); + crate::test_for_runtimes!([centrifuge], convert_dot); + crate::test_for_runtimes!([centrifuge], convert_unknown_multilocation); + crate::test_for_runtimes!([centrifuge], convert_unsupported_currency); + } + + mod restricted_calls { + use super::*; + + fn xtokens_transfer() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + // For now, Tranche tokens are not supported in the XCM config so + // we just safe-guard that trying to transfer a tranche token fails. + 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 + ); + }); + } + + // Verify that trying to transfer Tranche tokens using their MultiLocation + // representation also fails. + fn xtokens_transfer_multiasset() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + 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), + ))); + + 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()); + + 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), + )); + + 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!([centrifuge], xtokens_transfer); + crate::test_for_runtimes!([centrifuge], xtokens_transfer_multiasset); + crate::test_for_runtimes!([centrifuge], xtokens_transfer_multiassets); + } + + mod transfers { + use super::*; + + fn transfer_cfg_to_sibling(env: &mut FudgeEnv) { + let alice_initial_balance = cfg(10); + let bob_initial_balance = cfg(10); + let transfer_amount = cfg(1); + let transfer_amount = cfg(5); + let cfg_in_sibling = CurrencyId::ForeignAsset(12); + + // CFG Metadata + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Centrifuge".into(), + symbol: "CFG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(T::FudgeHandle::PARA_ID), + general_key(parachains::polkadot::centrifuge::CFG_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + 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 + ); + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta.clone(), + Some(CurrencyId::Native), + )); + }); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(cfg_in_sibling, &Keyring::Bob.into()), + 0 + ); + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(cfg_in_sibling) + )); + }); + + 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(cfg_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_cfg_transfers_to_and_from_sibling() { + let mut env = FudgeEnv::::from_storage( + Genesis::default() + .add(genesis::balances::(cfg(10))) + .storage(), + Default::default(), + ); + + setup_xcm(&mut env); + + // In order to be able to transfer CFG from Sibling to Centrifuge, we need to + // first send CFG from Centrifuge to Sibling, or else it fails since it'd be + // like Sibling had minted CFG on their side. + transfer_cfg_to_sibling(&mut env); + + let alice_initial_balance = cfg(5); + let bob_initial_balance = cfg(5) - cfg_fee(); + let transfer_amount = cfg(1); + // Note: This asset was registered in `transfer_cfg_to_sibling` + let cfg_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(cfg_in_sibling, &Keyring::Bob.into()), + bob_initial_balance + ); + }); + + env.sibling_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Bob.into()).into(), + cfg_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(cfg_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 - cfg_fee(), + ); + }); + } + + fn transfer_ausd_to_centrifuge() { + 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 centrifuge 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_dot_from_relay_chain(env: &mut FudgeEnv) { + let alice_initial_dot = dot(10); + let transfer_amount: Balance = dot(3); + + env.parachain_state_mut(|| { + register_dot::(); + assert_eq!( + orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.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(), + alice_initial_dot, + ) + ); + + 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::Alice.into(), + } + .into() + ), + Box::new((Here, transfer_amount).into()), + 0 + ) + ); + + assert_eq!( + pallet_balances::Pallet::>::free_balance( + &Keyring::Alice.into() + ), + alice_initial_dot - transfer_amount + ); + }); + + env.pass(Blocks::ByNumber(1)); + + env.parachain_state(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.into()), + transfer_amount - dot_fee() + ); + }); + } + + fn transfer_dot_to_and_from_relay_chain() { + let mut env = FudgeEnv::::from_storage(Default::default(), Default::default()); + + transfer_dot_from_relay_chain(&mut env); + + env.parachain_state_mut(|| { + let alice_initial_dot = + orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.into()); + + assert_eq!(alice_initial_dot, dot(3) - dot_fee()); + + 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::Alice.into()).into(), + DOT_ASSET_ID, + dot(1), + Box::new( + MultiLocation::new( + 1, + X1(Junction::AccountId32 { + id: Keyring::Alice.into(), + network: None, + }) + ) + .into() + ), + WeightLimit::Unlimited, + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.into()), + alice_initial_dot - dot(1), + ); + }); + + env.pass(Blocks::ByNumber(1)); + + env.relay_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::>::free_balance( + &Keyring::Alice.into() + ), + 79628418552 + ); + }); + } + + fn transfer_foreign_sibling_to_centrifuge() { + let mut env = FudgeEnv::::from_storage( + Genesis::default() + .add(genesis::balances::(cfg(10))) + .storage(), + Default::default(), + ); + + setup_xcm(&mut env); + + let alice_initial_balance = cfg(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(|| { + // First, register the asset in centrifuge + 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_acala_to_centrifuge() { + let mut env = FudgeEnv::::from_storage( + Default::default(), + Genesis::default() + .add(genesis::balances::(cfg(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()), + cfg(10) + ); + }); + + env.parachain_state_mut(|| { + 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!([centrifuge], test_cfg_transfers_to_and_from_sibling); + crate::test_for_runtimes!([centrifuge], transfer_ausd_to_centrifuge); + crate::test_for_runtimes!([centrifuge], transfer_dot_to_and_from_relay_chain); + crate::test_for_runtimes!([centrifuge], transfer_foreign_sibling_to_centrifuge); + crate::test_for_runtimes!([centrifuge], transfer_wormhole_usdc_acala_to_centrifuge); + } +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index 1a00fecef4..8d5cb3b9f4 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -53,7 +53,6 @@ use xcm::{ v3::{Junction, Junctions}, VersionedMultiLocation, }; -use xcm_simulator::TestExt; use crate::{ chain::{ diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 07ab739641..c784aefb8a 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -64,7 +64,6 @@ use sp_runtime::{ WeakBoundedVec, }; use tokio::runtime::Handle; -use xcm_simulator::TestExt; use crate::{ chain::centrifuge::{ diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs index 556d77b3f3..17c81ded9b 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -46,7 +46,6 @@ use sp_runtime::{ }; use tokio::runtime::Handle; use xcm::{latest::MultiLocation, VersionedMultiLocation}; -use xcm_simulator::TestExt; use crate::{ chain::centrifuge::{ diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs index dbc8c33e6e..99e1f58079 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs @@ -35,7 +35,6 @@ use runtime_common::{xcm::general_key, xcm_fees::default_per_second}; use sp_core::{bounded::BoundedVec, H160}; use sp_runtime::Storage; use tokio::runtime::Handle; -use xcm_simulator::TestExt; use crate::{ chain::centrifuge::{ diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs index d9fc7c1b7e..1f17d1fc75 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs @@ -42,7 +42,6 @@ use xcm::{ v3::{Junction, Junction::*, Junctions, Junctions::*, MultiLocation, NetworkId, WeightLimit}, VersionedMultiLocation, }; -use xcm_simulator::TestExt; use crate::{ chain::{ @@ -52,12 +51,9 @@ use crate::{ }, relay::{Hrmp as RelayHrmp, RuntimeOrigin as RelayRuntimeOrigin}, }, - liquidity_pools::pallet::{ - development::{ - setup::{centrifuge_account, cfg, sibling_account}, - tests::register_ausd, - }, - xcm_metadata, + liquidity_pools::pallet::development::{ + setup::{centrifuge_account, cfg, sibling_account}, + tests::register_ausd, }, utils::{ accounts::Keyring, @@ -349,3 +345,12 @@ fn calc_fee(fee_per_second: Balance) -> Balance { // shall see. fee_per_second.div_euclid(10_000) * 8 } + +/// Get the `XcmMetadata` for a given `CrossChainTransferability` value if +/// possible. +fn xcm_metadata(transferability: CrossChainTransferability) -> Option { + match transferability { + CrossChainTransferability::Xcm(x) | CrossChainTransferability::All(x) => Some(x), + _ => None, + } +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/mod.rs index 2a807c35ca..40b4e588a2 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/mod.rs @@ -13,14 +13,3 @@ use cfg_types::{tokens::CrossChainTransferability, xcm::XcmMetadata}; mod development; -mod kusama; -mod polkadot; - -/// Get the `XcmMetadata` for a given `CrossChainTransferability` value if -/// possible. -fn xcm_metadata(transferability: CrossChainTransferability) -> Option { - match transferability { - CrossChainTransferability::Xcm(x) | CrossChainTransferability::All(x) => Some(x), - _ => None, - } -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/mod.rs deleted file mode 100644 index 34f13591a7..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod setup; -mod test_net; -mod tests; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/setup.rs deleted file mode 100644 index e6fa66adf9..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/setup.rs +++ /dev/null @@ -1,143 +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. - -use altair_runtime::constants; -pub use centrifuge_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 DOT -pub const DOT_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(91); -/// An Asset that is NOT XCM transferable -pub const NO_XCM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(401); - -pub struct ExtBuilder { - balances: Vec<(AccountId, CurrencyId, Balance)>, - parachain_id: u32, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { - balances: vec![], - parachain_id: parachains::polkadot::centrifuge::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 = centrifuge_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 cfg(amount: Balance) -> Balance { - amount * dollar(currency_decimals::NATIVE) -} - -pub fn ausd(amount: Balance) -> Balance { - amount * dollar(currency_decimals::AUSD) -} - -pub fn dot(amount: Balance) -> Balance { - amount * dollar(10) -} - -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 acala_account() -> AccountId { - parachain_account(parachains::polkadot::acala::ID) -} - -pub fn centrifuge_account() -> AccountId { - parachain_account(parachains::polkadot::centrifuge::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/polkadot/test_net.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/test_net.rs deleted file mode 100644 index 1f993c4913..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/test_net.rs +++ /dev/null @@ -1,136 +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 centrifuge_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::{cfg, dot, ExtBuilder, ALICE, BOB, DOT_ASSET_ID, PARA_ID_SIBLING}; - -decl_test_relay_chain! { - pub struct PolkadotNet { - Runtime = polkadot_runtime::Runtime, - RuntimeCall = polkadot_runtime::RuntimeCall, - RuntimeEvent = polkadot_runtime::RuntimeEvent, - XcmConfig = polkadot_runtime::xcm_config::XcmConfig, - MessageQueue = polkadot_runtime::MessageQueue, - System = polkadot_runtime::System, - new_ext = relay_ext(), - } -} - -decl_test_parachain! { - pub struct Centrifuge { - Runtime = centrifuge_runtime::Runtime, - XcmpMessageHandler = centrifuge_runtime::XcmpQueue, - DmpMessageHandler = centrifuge_runtime::DmpQueue, - new_ext = para_ext(parachains::polkadot::centrifuge::ID), - } -} - -decl_test_parachain! { - pub struct Sibling { - Runtime = centrifuge_runtime::Runtime, - XcmpMessageHandler = centrifuge_runtime::XcmpQueue, - DmpMessageHandler = centrifuge_runtime::DmpQueue, - new_ext = para_ext(PARA_ID_SIBLING), - } -} - -decl_test_parachain! { - pub struct Acala { - Runtime = centrifuge_runtime::Runtime, - XcmpMessageHandler = centrifuge_runtime::XcmpQueue, - DmpMessageHandler = centrifuge_runtime::DmpQueue, - new_ext = para_ext(parachains::polkadot::acala::ID), - } -} - -decl_test_network! { - pub struct TestNet { - relay_chain = PolkadotNet, - 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::polkadot::centrifuge::ID` - (2031, Centrifuge), - // Be sure to use `PARA_ID_SIBLING` - (3000, Sibling), - // Be sure to use `parachains::polkadot::acala::ID` - (2000, Acala), - ], - } -} - -pub fn relay_ext() -> sp_io::TestExternalities { - use polkadot_runtime::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![(AccountId::from(ALICE), dot(10))], - } - .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, cfg(10)), - (AccountId::from(BOB), CurrencyId::Native, cfg(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/polkadot/tests/asset_registry.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/asset_registry.rs deleted file mode 100644 index e83ab08e1d..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/asset_registry.rs +++ /dev/null @@ -1,133 +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 centrifuge_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_err, assert_noop, assert_ok, error::BadOrigin}; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use runtime_common::{ - xcm::general_key, - xcm_fees::{default_per_second, ksm_per_second}, -}; -use xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - VersionedMultiLocation, -}; -use xcm_simulator::TestExt; - -use crate::liquidity_pools::pallet::polkadot::{ - setup::{ - acala_account, ausd, centrifuge_account, cfg, dot, foreign, sibling_account, ALICE, BOB, - DOT_ASSET_ID, PARA_ID_SIBLING, - }, - test_net::{Acala, Centrifuge, PolkadotNet, Sibling, TestNet}, -}; - -#[test] -fn register_cfg_works() { - Centrifuge::execute_with(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Centrifuge".into(), - symbol: "CFG".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 0, - X1(general_key(parachains::polkadot::centrifuge::CFG_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() { - Centrifuge::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::polkadot::acala::ID), - general_key(parachains::polkadot::acala::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() { - Centrifuge::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/polkadot/tests/currency_id_convert.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/currency_id_convert.rs deleted file mode 100644 index a9e4dcbfe8..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/currency_id_convert.rs +++ /dev/null @@ -1,223 +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 centrifuge_runtime::{ - Balances, CurrencyIdConvert, OrmlAssetRegistry, OrmlTokens, 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_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::{ConstU32, Convert as C2}, - WeakBoundedVec, -}; -use xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - VersionedMultiLocation, -}; -use xcm_executor::traits::Convert as C1; -use xcm_simulator::TestExt; - -use super::register_dot; -use crate::{ - liquidity_pools::pallet::polkadot::{ - setup::{ - acala_account, ausd, centrifuge_account, cfg, dot, foreign, sibling_account, ALICE, - BOB, DOT_ASSET_ID, NO_XCM_ASSET_ID, PARA_ID_SIBLING, - }, - test_net::{Acala, Centrifuge, PolkadotNet, Sibling, TestNet}, - tests::{register_ausd, register_cfg, register_cfg_v2, register_no_xcm_token}, - }, - utils::AUSD_CURRENCY_ID, -}; - -#[test] -fn convert_cfg() { - assert_eq!(parachains::polkadot::centrifuge::CFG_KEY, &[0, 1]); - - Centrifuge::execute_with(|| { - // The way CFG is represented relative within the Centrifuge runtime - let cfg_location_inner: MultiLocation = MultiLocation::new( - 0, - X1(general_key(parachains::polkadot::centrifuge::CFG_KEY)), - ); - - register_cfg(); - - assert_eq!( - >::convert(cfg_location_inner), - Ok(CurrencyId::Native), - ); - - // The canonical way CFG is represented out in the wild - let cfg_location_canonical: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::ID), - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ), - ); - - assert_eq!( - >::convert(CurrencyId::Native), - Some(cfg_location_canonical) - ) - }); -} - -/// Verify that even with CFG registered in the AssetRegistry with a XCM v2 -/// MultiLocation, that `CurrencyIdConvert` can look it up given an identical -/// location in XCM v3. -#[test] -fn convert_cfg_xcm_v2() { - assert_eq!(parachains::polkadot::centrifuge::CFG_KEY, &[0, 1]); - - Centrifuge::execute_with(|| { - // Registered as xcm v2 - register_cfg_v2(); - - // The way CFG is represented relative within the Centrifuge runtime in xcm v3 - let cfg_location_inner: MultiLocation = MultiLocation::new( - 0, - X1(general_key(parachains::polkadot::centrifuge::CFG_KEY)), - ); - - assert_eq!( - >::convert(cfg_location_inner), - Ok(CurrencyId::Native), - ); - - // The canonical way CFG is represented out in the wild - let cfg_location_canonical: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::ID), - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ), - ); - - assert_eq!( - >::convert(CurrencyId::Native), - Some(cfg_location_canonical) - ) - }); -} - -/// Verify that a registered token that is NOT XCM transferable is filtered out -/// by CurrencyIdConvert as expected. -#[test] -fn convert_no_xcm_token() { - Centrifuge::execute_with(|| { - register_no_xcm_token(); - - assert_eq!( - >::convert(NO_XCM_ASSET_ID), - None - ) - }); -} - -#[test] -fn convert_ausd() { - assert_eq!(parachains::polkadot::acala::AUSD_KEY, &[0, 1]); - - let ausd_location: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::acala::ID), - general_key(parachains::polkadot::acala::AUSD_KEY), - ), - ); - - Centrifuge::execute_with(|| { - register_ausd(); - - assert_eq!( - >::convert(ausd_location), - Ok(AUSD_CURRENCY_ID), - ); - - assert_eq!( - >::convert(AUSD_CURRENCY_ID), - Some(ausd_location) - ) - }); -} - -#[test] -fn convert_dot() { - let dot_location: MultiLocation = MultiLocation::parent(); - - Centrifuge::execute_with(|| { - register_dot(); - - assert_eq!( - >::convert(dot_location), - Ok(DOT_ASSET_ID), - ); - - assert_eq!( - >::convert(DOT_ASSET_ID), - Some(dot_location) - ) - }); -} - -#[test] -fn convert_unknown_multilocation() { - let unknown_location: MultiLocation = MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::ID), - general_key([42].as_ref()), - ), - ); - - Centrifuge::execute_with(|| { - assert!(>::convert(unknown_location).is_err()); - }); -} - -#[test] -fn convert_unsupported_currency() { - Centrifuge::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/polkadot/tests/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/mod.rs deleted file mode 100644 index 7b9a9348bf..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/mod.rs +++ /dev/null @@ -1,166 +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. - -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 sp_core::{bounded::WeakBoundedVec, ConstU32}; -use xcm::{ - latest::MultiLocation, - prelude::{Parachain, X2}, - VersionedMultiLocation, -}; - -use crate::{ - liquidity_pools::pallet::polkadot::setup::{DOT_ASSET_ID, NO_XCM_ASSET_ID}, - utils::AUSD_CURRENCY_ID, -}; - -mod asset_registry; -mod currency_id_convert; -mod restricted_calls; -mod transfers; - -/// Register DOT in the asset registry. -/// It should be executed within an externalities environment. -fn register_dot() { - let meta: AssetMetadata = AssetMetadata { - decimals: 10, - name: "Polkadot".into(), - symbol: "DOT".into(), - existential_deposit: 100_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::parent())), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(DOT_ASSET_ID) - )); -} - -/// 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_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::acala::ID), - general_key(parachains::polkadot::acala::AUSD_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(AUSD_CURRENCY_ID) - )); -} - -/// Register CFG in the asset registry. -/// It should be executed within an externalities environment. -fn register_cfg() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Centrifuge".into(), - symbol: "CFG".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::ID), - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); -} - -/// Register CFG in the asset registry as XCM v2, just like it is in production. -/// It should be executed within an externalities environment. -fn register_cfg_v2() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Centrifuge".into(), - symbol: "CFG".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V2(xcm::v2::MultiLocation::new( - 1, - xcm::v2::Junctions::X2( - xcm::v2::Junction::Parachain(parachains::polkadot::centrifuge::ID), - xcm::v2::Junction::GeneralKey(WeakBoundedVec::>::force_from( - parachains::polkadot::centrifuge::CFG_KEY.into(), - None, - )), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); -} - -/// Register a token whose `CrossChainTransferability` does NOT include XCM. -fn register_no_xcm_token() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "NO XCM".into(), - symbol: "NXCM".into(), - existential_deposit: 1_000_000_000_000, - location: None, - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - ..CustomMetadata::default() - }, - }; - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(NO_XCM_ASSET_ID) - )); -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/restricted_calls.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/restricted_calls.rs deleted file mode 100644 index cdac5b02d0..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/restricted_calls.rs +++ /dev/null @@ -1,196 +0,0 @@ -// 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 centrifuge_runtime::{Balances, Multisig, PolkadotXcm, RuntimeCall, RuntimeOrigin, XTokens}; -use cfg_primitives::{constants::currency_decimals, parachains, Balance}; -use cfg_types::{ - tokens::{CurrencyId, CustomMetadata}, - xcm::XcmMetadata, -}; -use codec::Encode; -use frame_support::{ - assert_err, assert_noop, assert_ok, dispatch::Dispatchable, traits::WrapperKeepOpaque, -}; -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::polkadot::{ - setup::{ - acala_account, ausd, centrifuge_account, cfg, dot, foreign, sibling_account, ALICE, BOB, - DOT_ASSET_ID, PARA_ID_SIBLING, - }, - test_net::{Acala, Centrifuge, PolkadotNet, 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 frame_support::weights::Weight; - 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. - Centrifuge::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), - ))); - - Centrifuge::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), - )); - - Centrifuge::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/polkadot/tests/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/transfers.rs deleted file mode 100644 index 1743c1f492..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/polkadot/tests/transfers.rs +++ /dev/null @@ -1,591 +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 centrifuge_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::traits::BadOrigin; -use xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId, WeightLimit}, - VersionedMultiLocation, -}; -use xcm_simulator::TestExt; - -use super::register_dot; -use crate::{ - liquidity_pools::pallet::{ - polkadot::{ - setup::{ - acala_account, ausd, centrifuge_account, cfg, dot, foreign, sibling_account, ALICE, - BOB, DOT_ASSET_ID, PARA_ID_SIBLING, - }, - test_net::{Acala, Centrifuge, PolkadotNet, 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_cfg_to_sibling() { - TestNet::reset(); - - let alice_initial_balance = cfg(10); - let bob_initial_balance = cfg(10); - let transfer_amount = cfg(1); - let transfer_amount = cfg(5); - let cfg_in_sibling = CurrencyId::ForeignAsset(12); - - // CFG Metadata - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: "Centrifuge".into(), - symbol: "CFG".into(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::ID), - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - - Centrifuge::execute_with(|| { - assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); - assert_eq!(Balances::free_balance(&sibling_account()), 0); - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(CurrencyId::Native), - )); - }); - - Sibling::execute_with(|| { - assert_eq!(OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()), 0); - - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta, - Some(cfg_in_sibling) - )); - }); - - Centrifuge::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(cfg_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_cfg_sibling_to_centrifuge() { - TestNet::reset(); - - // In order to be able to transfer CFG from Sibling to Centrifuge, we need to - // first send CFG from Centrifuge to Sibling, or else it fails since it'd be - // like Sibling had minted CFG on their side. - transfer_cfg_to_sibling(); - - let alice_initial_balance = cfg(5); - let bob_initial_balance = cfg(5) - cfg_fee(); - let transfer_amount = cfg(1); - // Note: This asset was registered in `transfer_cfg_to_sibling` - let cfg_in_sibling = CurrencyId::ForeignAsset(12); - - Centrifuge::execute_with(|| { - assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); - }); - - Sibling::execute_with(|| { - assert_eq!(Balances::free_balance(¢rifuge_account()), 0); - assert_eq!( - OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()), - bob_initial_balance - ); - }); - - Sibling::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(BOB.into()), - cfg_in_sibling, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::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(cfg_in_sibling, &BOB.into()), - bob_initial_balance - transfer_amount - ); - }); - - Centrifuge::execute_with(|| { - // Verify that ALICE now has initial balance + amount transferred - fee - assert_eq!( - Balances::free_balance(&ALICE.into()), - alice_initial_balance + transfer_amount - cfg_fee(), - ); - }); -} - -#[test] -fn transfer_ausd_to_centrifuge() { - TestNet::reset(); - - let alice_initial_balance = ausd(10); - let transfer_amount = ausd(7); - - Acala::execute_with(|| { - register_ausd(); - - assert_ok!(OrmlTokens::deposit( - AUSD_CURRENCY_ID, - &ALICE.into(), - alice_initial_balance - )); - - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, ¢rifuge_account()), - 0 - ); - }); - - Centrifuge::execute_with(|| { - register_ausd(); - - assert_eq!(OrmlTokens::free_balance(AUSD_CURRENCY_ID, &BOB.into()), 0,); - }); - - Acala::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::polkadot::centrifuge::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 centrifuge parachain - // account here - assert_eq!( - OrmlTokens::free_balance(AUSD_CURRENCY_ID, ¢rifuge_account()), - transfer_amount - ); - }); - - Centrifuge::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_dot_from_relay_chain() { - let alice_initial_dot = dot(10); - let transfer_amount: Balance = dot(3); - - Centrifuge::execute_with(|| { - register_dot(); - assert_eq!(OrmlTokens::free_balance(DOT_ASSET_ID, &ALICE.into()), 0); - }); - - PolkadotNet::execute_with(|| { - assert_eq!( - polkadot_runtime::Balances::free_balance(&ALICE.into()), - alice_initial_dot - ); - - assert_ok!(polkadot_runtime::XcmPallet::reserve_transfer_assets( - polkadot_runtime::RuntimeOrigin::signed(ALICE.into()), - Box::new(Parachain(parachains::polkadot::centrifuge::ID).into()), - Box::new( - Junction::AccountId32 { - network: None, - id: ALICE, - } - .into() - ), - Box::new((Here, transfer_amount).into()), - 0 - )); - - assert_eq!( - polkadot_runtime::Balances::free_balance(&ALICE.into()), - alice_initial_dot - transfer_amount - ); - }); - - Centrifuge::execute_with(|| { - assert_eq!( - OrmlTokens::free_balance(DOT_ASSET_ID, &ALICE.into()), - transfer_amount - dot_fee() - ); - }); -} - -#[test] -fn transfer_dot_to_relay_chain() { - transfer_dot_from_relay_chain(); - - Centrifuge::execute_with(|| { - let alice_initial_dot = OrmlTokens::free_balance(DOT_ASSET_ID, &ALICE.into()); - - assert_eq!(alice_initial_dot, dot(3) - dot_fee(),); - - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - DOT_ASSET_ID, - dot(1), - Box::new( - MultiLocation::new( - 1, - X1(Junction::AccountId32 { - id: ALICE, - network: None, - }) - ) - .into() - ), - WeightLimit::Unlimited, - )); - - assert_eq!( - OrmlTokens::free_balance(DOT_ASSET_ID, &ALICE.into()), - alice_initial_dot - dot(1), - ); - }); - - PolkadotNet::execute_with(|| { - assert_eq!( - polkadot_runtime::Balances::free_balance(&ALICE.into()), - 79637471000 - ); - }); -} - -#[test] -fn transfer_foreign_sibling_to_centrifuge() { - TestNet::reset(); - - let alice_initial_balance = cfg(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), - )); - }); - - Centrifuge::execute_with(|| { - // First, register the asset in centrifuge - 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::polkadot::centrifuge::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 - ); - }); - - Centrifuge::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_acala_to_centrifuge() { - TestNet::reset(); - - let usdc_asset_id = CurrencyId::ForeignAsset(39); - let asset_location = MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::acala::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; - - Acala::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()), cfg(10)); - }); - - Centrifuge::execute_with(|| { - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - meta.clone(), - Some(usdc_asset_id) - )); - }); - - Acala::execute_with(|| { - assert_ok!(XTokens::transfer( - RuntimeOrigin::signed(ALICE.into()), - usdc_asset_id, - transfer_amount, - Box::new( - MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::centrifuge::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 - ); - }); - - Centrifuge::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!(cfg_fee(), 8012800000000000); -} - -fn cfg_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 DOT tokens -fn dot_fee() -> Balance { - fee(10) -} - -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 -}