From ea08cecefb1cfa29bd663396d70d6734e344b2ad Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 11 Jun 2024 15:54:26 +0200 Subject: [PATCH 01/21] basic xtransfer tests --- libs/types/src/tokens.rs | 17 + .../src/generic/cases/investments.rs | 2 +- .../src/generic/cases/liquidity_pools.rs | 351 +----------------- .../src/generic/cases/loans.rs | 2 +- .../src/generic/cases/precompile.rs | 2 +- .../src/generic/cases/xtransfers.rs | 140 +++++++ runtime/integration-tests/src/generic/mod.rs | 1 + .../src/generic/utils/currency.rs | 57 ++- .../src/generic/utils/genesis.rs | 2 +- .../integration-tests/src/utils/accounts.rs | 4 + runtime/integration-tests/src/utils/mod.rs | 6 + 11 files changed, 228 insertions(+), 356 deletions(-) create mode 100644 runtime/integration-tests/src/generic/cases/xtransfers.rs diff --git a/libs/types/src/tokens.rs b/libs/types/src/tokens.rs index 495716e280..2d4f7e4311 100644 --- a/libs/types/src/tokens.rs +++ b/libs/types/src/tokens.rs @@ -364,6 +364,23 @@ impl CrossChainTransferability { pub fn includes_liquidity_pools(self) -> bool { matches!(self, Self::LiquidityPools) } + + /// Fees will charged using `FixedRateOfFungible`. + #[cfg(feature = "std")] + pub fn xcm_default() -> Self { + Self::Xcm(XcmMetadata { + fee_per_second: None, + }) + } + + /// Fees will charged using `AssetRegistryTrader`. + /// If value is 0, no fees will be charged. + #[cfg(feature = "std")] + pub fn xcm_with_fees(value: Balance) -> Self { + Self::Xcm(XcmMetadata { + fee_per_second: Some(value), + }) + } } /// Liquidity Pools-wrapped tokens diff --git a/runtime/integration-tests/src/generic/cases/investments.rs b/runtime/integration-tests/src/generic/cases/investments.rs index f229bde9f0..50672efaf2 100644 --- a/runtime/integration-tests/src/generic/cases/investments.rs +++ b/runtime/integration-tests/src/generic/cases/investments.rs @@ -43,7 +43,7 @@ mod common { .add(genesis::balances::( T::ExistentialDeposit::get() + FOR_FEES, )) - .add(genesis::assets::(vec![Box::new(Usd6)])) + .add(genesis::assets::(vec![&Usd6])) .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 5e36ed13c4..255d62526d 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -59,11 +59,8 @@ use sp_runtime::{ }; use staging_xcm::{ prelude::XCM_VERSION, - v4::{ - Asset, AssetId, Assets, Fungibility, Junction, Junction::*, Junctions, Junctions::*, - Location, NetworkId, WeightLimit, - }, - VersionedAsset, VersionedAssets, VersionedLocation, + v4::{Junction, Junction::*, Junctions, Junctions::*, Location, NetworkId, WeightLimit}, + VersionedLocation, }; use crate::{ @@ -76,15 +73,9 @@ use crate::{ genesis::Genesis, xcm::setup_xcm, }, }, - utils::accounts::Keyring, + utils::{accounts::Keyring, orml_asset_registry}, }; -mod orml_asset_registry { - // orml_asset_registry has remove the reexport of all pallet stuff, - // we reexport it again here - pub use orml_asset_registry::module::*; -} - /// The AUSD asset id pub const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(3); /// The USDT asset id @@ -5803,109 +5794,6 @@ mod altair { assert_eq!(bob_balance, 993264000000000000); }); } - - #[test_runtimes([altair])] - fn transfer_wormhole_usdc_karura_to_altair() { - let mut env = FudgeEnv::::from_storage( - Default::default(), - Default::default(), - Genesis::default() - .add(genesis::balances::(air(10))) - .storage(), - ); - - setup_xcm(&mut env); - - let usdc_asset_id = CurrencyId::ForeignAsset(39); - let asset_location = Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - general_key("0x02f3a00dd12f644daec907013b16eb6d14bf1c4cb4".as_bytes()), - ], - ); - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1, - location: Some(VersionedLocation::V4(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( - Location::new( - 1, - [ - 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(3)); - - 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, 11993571); - }); - } } mod asset_registry { @@ -7916,238 +7804,5 @@ mod centrifuge { assert_eq!(bob_balance, 993264000000000000); }); } - - #[test_runtimes([centrifuge])] - fn transfer_wormhole_usdc_acala_to_centrifuge() { - let mut env = FudgeEnv::::from_storage( - Default::default(), - Default::default(), - Genesis::default() - .add(genesis::balances::(cfg(10))) - .storage(), - ); - - setup_xcm(&mut env); - - let usdc_asset_id = CurrencyId::ForeignAsset(39); - let asset_location = Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - general_key("0x02f3a00dd12f644daec907013b16eb6d14bf1c4cb4".as_bytes()), - ], - ); - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1, - location: Some(VersionedLocation::V4(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( - Location::new( - 1, - [ - 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(3)); - - 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, 11993571); - }); - } - } -} - -mod all { - use super::*; - - mod restricted_calls { - use super::*; - - #[test_runtimes(all)] - fn xtokens_transfer() { - let mut env = FudgeEnv::::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( - Location::new( - 1, - [ - 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 - ); - }); - } - - #[test_runtimes(all)] - fn xtokens_transfer_multiasset() { - let mut env = FudgeEnv::::default(); - - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_location = Location::new( - 1, - [ - Parachain(123), - PalletInstance(42), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id.to_vec()), - }, - ], - ); - let tranche_asset = VersionedAsset::from(Asset::from(( - AssetId(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_asset), - Box::new( - Location::new( - 1, - [ - 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 - ); - }); - } - - #[test_runtimes(all)] - fn xtokens_transfer_multiassets() { - let mut env = FudgeEnv::::default(); - - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_location = Location::new( - 1, - [ - Parachain(123), - PalletInstance(42), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id.to_vec()), - }, - ], - ); - let tranche_asset = Asset::from((AssetId(tranche_location), Fungibility::Fungible(42))); - - env.parachain_state_mut(|| { - assert_noop!( - orml_xtokens::Pallet::::transfer_multiassets( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Box::new(VersionedAssets::from(Assets::from(vec![tranche_asset]))), - 0, - Box::new( - Location::new( - 1, - [ - 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 - ); - }); - } } } diff --git a/runtime/integration-tests/src/generic/cases/loans.rs b/runtime/integration-tests/src/generic/cases/loans.rs index dc995d7b6e..e3e806ab42 100644 --- a/runtime/integration-tests/src/generic/cases/loans.rs +++ b/runtime/integration-tests/src/generic/cases/loans.rs @@ -76,7 +76,7 @@ mod common { .add(genesis::balances::( T::ExistentialDeposit::get() + FOR_FEES, )) - .add(genesis::assets::(vec![Box::new(Usd6)])) + .add(genesis::assets::(vec![&Usd6])) .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/precompile.rs b/runtime/integration-tests/src/generic/cases/precompile.rs index d2e3d05df5..269e1a1d97 100644 --- a/runtime/integration-tests/src/generic/cases/precompile.rs +++ b/runtime/integration-tests/src/generic/cases/precompile.rs @@ -30,7 +30,7 @@ use crate::generic::{ fn axelar_precompile_execute() { RuntimeEnv::::from_parachain_storage( Genesis::default() - .add(genesis::assets::(vec![Box::new(Usd18)])) + .add(genesis::assets::(vec![&Usd18])) .storage(), ) .parachain_state_mut(|| { diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs new file mode 100644 index 0000000000..fb67216afe --- /dev/null +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -0,0 +1,140 @@ +use cfg_types::tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}; +use frame_support::{assert_ok, dispatch::RawOrigin}; +use orml_traits::MultiCurrency; +use staging_xcm::{ + v4::{Junction, Junction::*, Location, WeightLimit}, + VersionedLocation, +}; + +use crate::{ + generic::{ + config::Runtime, + env::{Blocks, Env}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, + utils::{ + currency::{cfg, CurrencyInfo, CustomCurrency}, + genesis, + genesis::Genesis, + xcm::setup_xcm, + }, + }, + utils::accounts::Keyring, +}; + +fn bob_in_sibling() -> Box { + Box::new( + Location::new( + 1, + [ + Parachain(T::FudgeHandle::SIBLING_ID), + Junction::from(Keyring::Bob.bytes()), + ], + ) + .into(), + ) +} + +#[test_runtimes(all)] +fn transfer_native_tokens_to_sibling() { + let native_curr = CustomCurrency { + id: CurrencyId::Native, + decimals: 18, + location: Location::new(1, Parachain(T::FudgeHandle::PARA_ID)), + custom: CustomMetadata { + transferability: CrossChainTransferability::xcm_with_fees(0), + ..Default::default() + }, + }; + + let xnative_curr = CustomCurrency { + id: CurrencyId::ForeignAsset(99), + ..native_curr.clone() + }; + + let mut env = FudgeEnv::::from_storage( + Default::default(), + Genesis::default() + .add(genesis::balances::(cfg(100))) + .add(genesis::assets::(vec![&native_curr])) + .storage(), + Genesis::default() + .add(genesis::assets::(vec![&xnative_curr])) + .storage(), + ); + + setup_xcm(&mut env); + + env.parachain_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + CurrencyId::Native, + cfg(80), + bob_in_sibling::(), + WeightLimit::Unlimited, + )); + + assert_eq!( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), + cfg(100) - cfg(80) + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(xnative_curr.id(), &Keyring::Bob.into()), + xnative_curr.val(80) + ); + }); +} + +#[test_runtimes(all)] +fn transfer_foreign_tokens_to_sibling() { + let curr = CustomCurrency { + id: 1.into(), + decimals: 6, + location: Location::new(1, Parachain(T::FudgeHandle::PARA_ID)), + custom: CustomMetadata { + transferability: CrossChainTransferability::xcm_with_fees(0), + ..Default::default() + }, + }; + + let mut env = FudgeEnv::::from_storage( + Default::default(), + Genesis::default() + .add(genesis::tokens::(vec![(curr.id(), curr.val(100))])) + .add(genesis::assets::(vec![&curr])) + .storage(), + Genesis::default() + .add(genesis::assets::(vec![&curr])) + .storage(), + ); + + setup_xcm(&mut env); + + env.parachain_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + curr.val(80), + bob_in_sibling::(), + WeightLimit::Unlimited, + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Alice.id()), + curr.val(100) - curr.val(80) + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), + curr.val(80) + ); + }); +} diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index 7a484368ed..66689ac2e7 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -20,6 +20,7 @@ mod cases { mod precompile; mod proxy; mod restricted_transfers; + mod xtransfers; } /// Generate tests for the specified runtimes or all runtimes. diff --git a/runtime/integration-tests/src/generic/utils/currency.rs b/runtime/integration-tests/src/generic/utils/currency.rs index 5715ae3171..ef3cf786c3 100644 --- a/runtime/integration-tests/src/generic/utils/currency.rs +++ b/runtime/integration-tests/src/generic/utils/currency.rs @@ -5,9 +5,22 @@ use cfg_primitives::{conversion, Balance, CFG}; use cfg_types::tokens::{AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata}; use frame_support::{assert_ok, traits::OriginTrait}; use sp_runtime::FixedPointNumber; +use staging_xcm::{v4::Location, VersionedLocation}; use crate::generic::config::Runtime; +pub const fn amount6(amount: Balance) -> Balance { + amount * 10u128.pow(6) +} + +pub const fn amount12(amount: Balance) -> Balance { + amount * 10u128.pow(12) +} + +pub const fn amount18(amount: Balance) -> Balance { + amount * 10u128.pow(18) +} + pub const fn cfg(amount: Balance) -> Balance { amount * CFG } @@ -31,7 +44,7 @@ pub trait CurrencyInfo { &self.symbol() } - fn location(&self) -> Option { + fn location(&self) -> Option { None } @@ -92,7 +105,7 @@ impl CurrencyInfo for Usd6 { } pub const fn usd6(amount: Balance) -> Balance { - amount * 10u128.pow(6) + amount6(amount) } pub struct Usd12; @@ -118,7 +131,7 @@ impl CurrencyInfo for Usd12 { } pub const fn usd12(amount: Balance) -> Balance { - amount * 10u128.pow(12) + amount12(amount) } pub struct Usd18; @@ -144,7 +157,43 @@ impl CurrencyInfo for Usd18 { } pub const fn usd18(amount: Balance) -> Balance { - amount * 10u128.pow(18) + amount18(amount) +} + +#[derive(Clone)] +pub struct CustomCurrency { + pub id: CurrencyId, + pub decimals: u32, + pub location: Location, + pub custom: CustomMetadata, +} + +impl CurrencyInfo for CustomCurrency { + fn id(&self) -> CurrencyId { + self.id + } + + fn decimals(&self) -> u32 { + self.decimals + } + + fn symbol(&self) -> &'static str { + format!("Custom-{}", self.decimals()).leak() + } + + fn location(&self) -> Option { + Some(VersionedLocation::V4(self.location.clone())) + } + + fn custom(&self) -> CustomMetadata { + self.custom + } +} + +impl CustomCurrency { + pub const fn val(&self, amount: Balance) -> Balance { + amount * 10u128.pow(self.decimals) + } } pub fn register_currency( diff --git a/runtime/integration-tests/src/generic/utils/genesis.rs b/runtime/integration-tests/src/generic/utils/genesis.rs index 4f6e306f7d..b26691e1ef 100644 --- a/runtime/integration-tests/src/generic/utils/genesis.rs +++ b/runtime/integration-tests/src/generic/utils/genesis.rs @@ -53,7 +53,7 @@ pub fn tokens(values: Vec<(CurrencyId, Balance)>) -> impl BuildStora } } -pub fn assets(currency_ids: Vec>) -> impl BuildStorage { +pub fn assets(currency_ids: Vec<&dyn CurrencyInfo>) -> impl BuildStorage { orml_asset_registry::module::GenesisConfig:: { assets: currency_ids .into_iter() diff --git a/runtime/integration-tests/src/utils/accounts.rs b/runtime/integration-tests/src/utils/accounts.rs index 0b38d5f9de..463e962f58 100644 --- a/runtime/integration-tests/src/utils/accounts.rs +++ b/runtime/integration-tests/src/utils/accounts.rs @@ -40,6 +40,10 @@ impl Keyring { self.to_account_id() } + pub fn bytes(self) -> [u8; 32] { + self.public().0 + } + pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } diff --git a/runtime/integration-tests/src/utils/mod.rs b/runtime/integration-tests/src/utils/mod.rs index f4f23fffaa..a6da19e701 100644 --- a/runtime/integration-tests/src/utils/mod.rs +++ b/runtime/integration-tests/src/utils/mod.rs @@ -12,3 +12,9 @@ pub mod accounts; pub mod logs; + +pub mod orml_asset_registry { + // orml_asset_registry has remove the reexport of all pallet stuff, + // we reexport it again here + pub use orml_asset_registry::module::*; +} From 0bc96f601b93abfe68266e048ce88a5b8f2a7893 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 11 Jun 2024 17:26:40 +0200 Subject: [PATCH 02/21] parachain transfer tested --- libs/types/src/tokens.rs | 4 +- .../src/generic/cases/investments.rs | 2 +- .../src/generic/cases/liquidity_pools.rs | 1091 +---------------- .../src/generic/cases/loans.rs | 2 +- .../src/generic/cases/oracles.rs | 8 +- .../src/generic/cases/precompile.rs | 2 +- .../src/generic/cases/xtransfers.rs | 136 +- .../src/generic/utils/currency.rs | 70 +- .../src/generic/utils/genesis.rs | 29 +- .../src/generic/utils/xcm.rs | 32 + .../integration-tests/src/utils/accounts.rs | 4 - 11 files changed, 216 insertions(+), 1164 deletions(-) diff --git a/libs/types/src/tokens.rs b/libs/types/src/tokens.rs index 2d4f7e4311..aefb80a73c 100644 --- a/libs/types/src/tokens.rs +++ b/libs/types/src/tokens.rs @@ -365,7 +365,7 @@ impl CrossChainTransferability { matches!(self, Self::LiquidityPools) } - /// Fees will charged using `FixedRateOfFungible`. + /// Fees will be charged using `FixedRateOfFungible`. #[cfg(feature = "std")] pub fn xcm_default() -> Self { Self::Xcm(XcmMetadata { @@ -373,7 +373,7 @@ impl CrossChainTransferability { }) } - /// Fees will charged using `AssetRegistryTrader`. + /// Fees will be charged using `AssetRegistryTrader`. /// If value is 0, no fees will be charged. #[cfg(feature = "std")] pub fn xcm_with_fees(value: Balance) -> Self { diff --git a/runtime/integration-tests/src/generic/cases/investments.rs b/runtime/integration-tests/src/generic/cases/investments.rs index 50672efaf2..946d98a779 100644 --- a/runtime/integration-tests/src/generic/cases/investments.rs +++ b/runtime/integration-tests/src/generic/cases/investments.rs @@ -43,7 +43,7 @@ mod common { .add(genesis::balances::( T::ExistentialDeposit::get() + FOR_FEES, )) - .add(genesis::assets::(vec![&Usd6])) + .add(genesis::assets::(vec![(Usd6.id(), &Usd6.metadata())])) .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 255d62526d..3cb300a6f3 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -4477,199 +4477,6 @@ mod development { ); }); } - - fn transfer_cfg_to_sibling(env: &mut FudgeEnv) { - let alice_initial_balance = cfg(1_000); - let transfer_amount = cfg(5); - let cfg_in_sibling = CurrencyId::ForeignAsset(12); - - // CFG Metadata - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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!(pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - CurrencyId::Native, - transfer_amount, - Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - network: None, - id: Keyring::Bob.into(), - }, - ], - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - // Confirm that Keyring::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(2)); - - env.sibling_state(|| { - 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, 4993570400000000000); - }); - } - - #[test_runtimes([development])] - fn transfer_cfg_to_and_from_sibling() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - // In order to be able to transfer CFG from Moonbeam to Development, we need to - // first send CFG from Development to Moonbeam, or else it fails since it'd be - // like Moonbeam had minted CFG on their side. - transfer_cfg_to_sibling::(&mut env); - - let para_to_sibling_transfer_amount = cfg(5); - - let alice_balance = cfg(1_000) - para_to_sibling_transfer_amount; - let bob_balance = para_to_sibling_transfer_amount - fee(18); - let charlie_balance = cfg(1_000); - - let sibling_to_para_transfer_amount = cfg(4); - // Note: This asset was registered in `transfer_cfg_to_sibling` - let cfg_in_sibling = CurrencyId::ForeignAsset(12); - - env.parachain_state(|| { - assert_eq!( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), - alice_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_balance - ); - }); - - env.sibling_state_mut(|| { - assert_ok!(pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Bob.into()).into(), - cfg_in_sibling, - sibling_to_para_transfer_amount, - Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::PARA_ID), - Junction::AccountId32 { - network: None, - id: Keyring::Charlie.into(), - } - ] - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); - - // Confirm that Charlie's balance is initial balance - amount transferred - assert_eq!( - orml_tokens::Pallet::::free_balance(cfg_in_sibling, &Keyring::Bob.into()), - bob_balance - sibling_to_para_transfer_amount - ); - }); - - env.pass(Blocks::ByNumber(3)); - - env.parachain_state(|| { - // Verify that Charlie's balance equals the amount transferred - fee - assert_eq!( - pallet_balances::Pallet::::free_balance(&Into::::into( - Keyring::Charlie - )), - charlie_balance + sibling_to_para_transfer_amount - cfg_fee(), - ); - }); - } } mod routers { @@ -5261,369 +5068,71 @@ mod altair { mod transfers { use super::*; - fn transfer_air_to_sibling(env: &mut FudgeEnv) { - let alice_initial_balance = air(10); - let transfer_amount = air(5); - let air_in_sibling = CurrencyId::ForeignAsset(12); - + fn transfer_ksm_from_relay_chain( + env: &mut FudgeEnv, + transfer_amount: Balance, + currency_id: CurrencyId, + meta: AssetMetadata, + ) { 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: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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) + meta.clone(), + Some(currency_id), )); - }); - env.sibling_state_mut(|| { assert_eq!( - orml_tokens::Pallet::::free_balance(air_in_sibling, &Keyring::Bob.into()), + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), 0 ); - - // Register AIR as foreign asset in the sibling parachain - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - network: None, - id: Keyring::Bob.into(), - } - ] - ) - .into() - ), - WeightLimit::Limited(8_000_000_000_000.into()), - )); + env.relay_state_mut(|| { + assert_ok!( + pallet_balances::Pallet::>::force_set_balance( + as frame_system::Config>::RuntimeOrigin::root(), + as frame_system::Config>::Lookup::unlookup( + Keyring::Alice.id() + ), + transfer_amount * 2, + ) + ); - // 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 + assert_ok!( + pallet_xcm::Pallet::>::force_xcm_version( + as frame_system::Config>::RuntimeOrigin::root(), + Box::new(Location::new( + 0, + Junction::Parachain(T::FudgeHandle::PARA_ID), + )), + XCM_VERSION, + ) ); - // 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 + 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(2)); - 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, 4993570400000000000); - }); - } - - #[test_runtimes([altair])] - fn test_air_transfers_to_and_from_sibling() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(air(10))) - .storage(), - ); - - 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( - Location::new( - 1, - [ - 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(3)); - - 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(), - ); - }); - } - - #[test_runtimes([altair])] - fn transfer_ausd_to_altair() { - let mut env = FudgeEnv::::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( - Location::new( - 1, - [ - 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(3)); - - 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(), - as frame_system::Config>::Lookup::unlookup( - Keyring::Alice.id() - ), - transfer_amount * 2, - ) - ); - - assert_ok!( - pallet_xcm::Pallet::>::force_xcm_version( - as frame_system::Config>::RuntimeOrigin::root(), - Box::new(Location::new( - 0, - 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(2)); - - env.parachain_state(|| { - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), - 1991963000000 // Comes from `transfer_amount - fee(meta.decimals)` with noise - ); + env.parachain_state(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), + 1991963000000 // Comes from `transfer_amount - fee(meta.decimals)` with noise + ); }); } @@ -5686,114 +5195,6 @@ mod altair { ); }); } - - #[test_runtimes([altair])] - fn transfer_foreign_sibling_to_altair() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(air(10))) - .storage(), - ); - - setup_xcm(&mut env); - - let sibling_asset_id = CurrencyId::ForeignAsset(1); - let asset_location = Location::new( - 1, - [Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])], - ); - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(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( - Location::new( - 1, - [ - 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(3)); - - 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); - }); - } } mod asset_registry { @@ -7364,292 +6765,11 @@ mod centrifuge { mod transfers { use super::*; + #[test_runtimes([centrifuge])] + fn transfer_dot_to_and_from_relay_chain() { + let mut env = FudgeEnv::::default(); - fn transfer_cfg_to_sibling(env: &mut FudgeEnv) { - let alice_initial_balance = cfg(10); - let transfer_amount = cfg(5); - let cfg_in_sibling = CurrencyId::ForeignAsset(12); - - // CFG Metadata - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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( - Location::new( - 1, - [ - 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(2)); - - 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, 4993570400000000000); - }); - } - - #[test_runtimes([centrifuge])] - fn test_cfg_transfers_to_and_from_sibling() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .storage(), - ); - - 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( - Location::new( - 1, - [ - 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(3)); - - 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(), - ); - }); - } - - #[test_runtimes([centrifuge])] - fn transfer_ausd_to_centrifuge() { - let mut env = FudgeEnv::::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( - Location::new( - 1, - [ - 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(3)); - - 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() - ); - }); - } - - #[test_runtimes([centrifuge])] - fn transfer_dot_to_and_from_relay_chain() { - let mut env = FudgeEnv::::default(); - - transfer_dot_from_relay_chain(&mut env); + transfer_dot_from_relay_chain(&mut env); env.parachain_state_mut(|| { let alice_initial_dot = @@ -7695,114 +6815,5 @@ mod centrifuge { ); }); } - - #[test_runtimes([centrifuge])] - fn transfer_foreign_sibling_to_centrifuge() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .storage(), - ); - - setup_xcm(&mut env); - - let sibling_asset_id = CurrencyId::ForeignAsset(1); - let asset_location = Location::new( - 1, - [Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])], - ); - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(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( - Location::new( - 1, - [ - 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(3)); - - 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); - }); - } } } diff --git a/runtime/integration-tests/src/generic/cases/loans.rs b/runtime/integration-tests/src/generic/cases/loans.rs index e3e806ab42..4c506c77d1 100644 --- a/runtime/integration-tests/src/generic/cases/loans.rs +++ b/runtime/integration-tests/src/generic/cases/loans.rs @@ -76,7 +76,7 @@ mod common { .add(genesis::balances::( T::ExistentialDeposit::get() + FOR_FEES, )) - .add(genesis::assets::(vec![&Usd6])) + .add(genesis::assets::(vec![(Usd6.id(), &Usd6.metadata())])) .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/oracles.rs b/runtime/integration-tests/src/generic/cases/oracles.rs index 14124b582c..d194c50ea8 100644 --- a/runtime/integration-tests/src/generic/cases/oracles.rs +++ b/runtime/integration-tests/src/generic/cases/oracles.rs @@ -27,7 +27,7 @@ mod ratio_provider { config::Runtime, env::Env, envs::runtime_env::RuntimeEnv, - utils::currency::{register_currency, CurrencyInfo, CONST_DEFAULT_CUSTOM}, + utils::currency::{register_currency, CurrencyInfo}, }; pub struct OtherLocal; @@ -40,7 +40,7 @@ mod ratio_provider { CustomMetadata { pool_currency: true, transferability: CrossChainTransferability::None, - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } @@ -55,7 +55,7 @@ mod ratio_provider { CustomMetadata { pool_currency: true, transferability: CrossChainTransferability::None, - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } @@ -71,7 +71,7 @@ mod ratio_provider { pool_currency: true, transferability: CrossChainTransferability::LiquidityPools, local_representation: Some(LocalAssetId(1)), - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } diff --git a/runtime/integration-tests/src/generic/cases/precompile.rs b/runtime/integration-tests/src/generic/cases/precompile.rs index 269e1a1d97..aed0baa6eb 100644 --- a/runtime/integration-tests/src/generic/cases/precompile.rs +++ b/runtime/integration-tests/src/generic/cases/precompile.rs @@ -30,7 +30,7 @@ use crate::generic::{ fn axelar_precompile_execute() { RuntimeEnv::::from_parachain_storage( Genesis::default() - .add(genesis::assets::(vec![&Usd18])) + .add(genesis::assets::([(Usd18.id(), &Usd18.metadata())])) .storage(), ) .parachain_state_mut(|| { diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index fb67216afe..8886640755 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -1,10 +1,7 @@ -use cfg_types::tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}; +use cfg_types::tokens::CurrencyId; use frame_support::{assert_ok, dispatch::RawOrigin}; use orml_traits::MultiCurrency; -use staging_xcm::{ - v4::{Junction, Junction::*, Location, WeightLimit}, - VersionedLocation, -}; +use staging_xcm::v4::WeightLimit; use crate::{ generic::{ @@ -15,50 +12,70 @@ use crate::{ currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, genesis::Genesis, - xcm::setup_xcm, + xcm::{account_location, setup_xcm, transferable_metadata}, }, }, utils::accounts::Keyring, }; -fn bob_in_sibling() -> Box { - Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::from(Keyring::Bob.bytes()), - ], - ) - .into(), - ) -} +const INITIAL: u32 = 100; +const TRANSFER: u32 = 80; #[test_runtimes(all)] -fn transfer_native_tokens_to_sibling() { - let native_curr = CustomCurrency { - id: CurrencyId::Native, - decimals: 18, - location: Location::new(1, Parachain(T::FudgeHandle::PARA_ID)), - custom: CustomMetadata { - transferability: CrossChainTransferability::xcm_with_fees(0), - ..Default::default() - }, - }; +fn foreign_to_foreign_tokens() { + let curr = CustomCurrency(CurrencyId::ForeignAsset(1), transferable_metadata::(6)); + + let mut env = FudgeEnv::::from_storage( + Default::default(), + Genesis::default() + .add(genesis::tokens::([(curr.id(), curr.val(INITIAL))])) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .storage(), + Genesis::default() + .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .storage(), + ); + + setup_xcm(&mut env); + + env.parachain_state_mut(|| { + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.id()).into(), + curr.id(), + curr.val(TRANSFER), + account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), + WeightLimit::Unlimited, + )); - let xnative_curr = CustomCurrency { - id: CurrencyId::ForeignAsset(99), - ..native_curr.clone() - }; + assert_eq!( + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Alice.id()), + curr.val(INITIAL) - curr.val(TRANSFER) + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.sibling_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), + curr.val(TRANSFER) + ); + }); +} + +#[test_runtimes(all)] +fn native_to_foreign_tokens() { + let metadata = transferable_metadata::(18); + let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); let mut env = FudgeEnv::::from_storage( Default::default(), Genesis::default() - .add(genesis::balances::(cfg(100))) - .add(genesis::assets::(vec![&native_curr])) + .add(genesis::balances::(cfg(INITIAL))) + .add(genesis::assets::([(CurrencyId::Native, &metadata)])) .storage(), Genesis::default() - .add(genesis::assets::(vec![&xnative_curr])) + .add(genesis::assets::([(xnative.id(), &metadata)])) .storage(), ); @@ -66,16 +83,16 @@ fn transfer_native_tokens_to_sibling() { env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), + RawOrigin::Signed(Keyring::Alice.id()).into(), CurrencyId::Native, - cfg(80), - bob_in_sibling::(), + cfg(TRANSFER), + account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), WeightLimit::Unlimited, )); assert_eq!( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.into()), - cfg(100) - cfg(80) + pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), + cfg(INITIAL) - cfg(TRANSFER) ); }); @@ -83,32 +100,25 @@ fn transfer_native_tokens_to_sibling() { env.sibling_state_mut(|| { assert_eq!( - orml_tokens::Pallet::::free_balance(xnative_curr.id(), &Keyring::Bob.into()), - xnative_curr.val(80) + orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Bob.id()), + xnative.val(TRANSFER) ); }); } #[test_runtimes(all)] -fn transfer_foreign_tokens_to_sibling() { - let curr = CustomCurrency { - id: 1.into(), - decimals: 6, - location: Location::new(1, Parachain(T::FudgeHandle::PARA_ID)), - custom: CustomMetadata { - transferability: CrossChainTransferability::xcm_with_fees(0), - ..Default::default() - }, - }; +fn foreign_to_native_tokens() { + let metadata = transferable_metadata::(18); + let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); let mut env = FudgeEnv::::from_storage( Default::default(), Genesis::default() - .add(genesis::tokens::(vec![(curr.id(), curr.val(100))])) - .add(genesis::assets::(vec![&curr])) + .add(genesis::tokens::([(xnative.id(), xnative.val(INITIAL))])) + .add(genesis::assets::([(xnative.id(), &metadata)])) .storage(), Genesis::default() - .add(genesis::assets::(vec![&curr])) + .add(genesis::assets::([(CurrencyId::Native, &metadata)])) .storage(), ); @@ -116,16 +126,16 @@ fn transfer_foreign_tokens_to_sibling() { env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - curr.id(), - curr.val(80), - bob_in_sibling::(), + RawOrigin::Signed(Keyring::Alice.id()).into(), + xnative.id(), + xnative.val(TRANSFER), + account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), WeightLimit::Unlimited, )); assert_eq!( - orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Alice.id()), - curr.val(100) - curr.val(80) + orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Bob.id()), + xnative.val(INITIAL) - xnative.val(TRANSFER) ); }); @@ -133,8 +143,8 @@ fn transfer_foreign_tokens_to_sibling() { env.sibling_state_mut(|| { assert_eq!( - orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), - curr.val(80) + pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), + cfg(TRANSFER) ); }); } diff --git a/runtime/integration-tests/src/generic/utils/currency.rs b/runtime/integration-tests/src/generic/utils/currency.rs index ef3cf786c3..b53cb4815c 100644 --- a/runtime/integration-tests/src/generic/utils/currency.rs +++ b/runtime/integration-tests/src/generic/utils/currency.rs @@ -2,27 +2,30 @@ //! considered at this level. use cfg_primitives::{conversion, Balance, CFG}; -use cfg_types::tokens::{AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata}; +use cfg_types::tokens::{AssetMetadata, CurrencyId, CustomMetadata}; use frame_support::{assert_ok, traits::OriginTrait}; use sp_runtime::FixedPointNumber; -use staging_xcm::{v4::Location, VersionedLocation}; +use staging_xcm::VersionedLocation; use crate::generic::config::Runtime; -pub const fn amount6(amount: Balance) -> Balance { - amount * 10u128.pow(6) -} - -pub const fn amount12(amount: Balance) -> Balance { - amount * 10u128.pow(12) +pub fn default_metadata() -> AssetMetadata { + AssetMetadata { + decimals: 0, + name: Default::default(), + symbol: Default::default(), + existential_deposit: 0, + location: None, + additional: Default::default(), + } } -pub const fn amount18(amount: Balance) -> Balance { - amount * 10u128.pow(18) +const fn amount_pow(amount: Balance, exp: u32) -> Balance { + amount * 10u128.pow(exp) } -pub const fn cfg(amount: Balance) -> Balance { - amount * CFG +pub const fn cfg(amount: u32) -> Balance { + amount as Balance * CFG } pub trait CurrencyInfo { @@ -66,15 +69,6 @@ pub trait CurrencyInfo { } } -/// Matches default() but for const support -pub const CONST_DEFAULT_CUSTOM: CustomMetadata = CustomMetadata { - transferability: CrossChainTransferability::None, - mintable: false, - permissioned: false, - pool_currency: false, - local_representation: None, -}; - pub fn price_to_currency>( price: N, currency_id: impl CurrencyInfo, @@ -99,13 +93,13 @@ impl CurrencyInfo for Usd6 { fn custom(&self) -> CustomMetadata { CustomMetadata { pool_currency: true, - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } pub const fn usd6(amount: Balance) -> Balance { - amount6(amount) + amount_pow(amount, 6) } pub struct Usd12; @@ -125,13 +119,13 @@ impl CurrencyInfo for Usd12 { fn custom(&self) -> CustomMetadata { CustomMetadata { pool_currency: true, - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } pub const fn usd12(amount: Balance) -> Balance { - amount12(amount) + amount_pow(amount, 12) } pub struct Usd18; @@ -151,30 +145,24 @@ impl CurrencyInfo for Usd18 { fn custom(&self) -> CustomMetadata { CustomMetadata { pool_currency: true, - ..CONST_DEFAULT_CUSTOM + ..Default::default() } } } pub const fn usd18(amount: Balance) -> Balance { - amount18(amount) + amount_pow(amount, 18) } #[derive(Clone)] -pub struct CustomCurrency { - pub id: CurrencyId, - pub decimals: u32, - pub location: Location, - pub custom: CustomMetadata, -} - +pub struct CustomCurrency(pub CurrencyId, pub AssetMetadata); impl CurrencyInfo for CustomCurrency { fn id(&self) -> CurrencyId { - self.id + self.0 } fn decimals(&self) -> u32 { - self.decimals + self.1.decimals } fn symbol(&self) -> &'static str { @@ -182,17 +170,19 @@ impl CurrencyInfo for CustomCurrency { } fn location(&self) -> Option { - Some(VersionedLocation::V4(self.location.clone())) + self.1.location.clone() } fn custom(&self) -> CustomMetadata { - self.custom + self.1.additional } } impl CustomCurrency { - pub const fn val(&self, amount: Balance) -> Balance { - amount * 10u128.pow(self.decimals) + // Using `u32` on purpose here to avoid placing a `Balance` as input and + // generating more decimals than expected. + pub const fn val(&self, amount: u32) -> Balance { + amount_pow(amount as Balance, self.1.decimals) } } diff --git a/runtime/integration-tests/src/generic/utils/genesis.rs b/runtime/integration-tests/src/generic/utils/genesis.rs index b26691e1ef..a87b470184 100644 --- a/runtime/integration-tests/src/generic/utils/genesis.rs +++ b/runtime/integration-tests/src/generic/utils/genesis.rs @@ -2,13 +2,16 @@ //! considered at this level. use cfg_primitives::Balance; -use cfg_types::{fixed_point::Rate, tokens::CurrencyId}; +use cfg_types::{ + fixed_point::Rate, + tokens::{AssetMetadata, CurrencyId}, +}; use parity_scale_codec::Encode; use sp_core::Get; use sp_runtime::{BuildStorage, FixedPointNumber, Storage}; use crate::{ - generic::{config::Runtime, utils::currency::CurrencyInfo}, + generic::config::Runtime, utils::accounts::{default_accounts, Keyring}, }; @@ -37,7 +40,9 @@ pub fn balances(balance: Balance) -> impl BuildStorage { } } -pub fn tokens(values: Vec<(CurrencyId, Balance)>) -> impl BuildStorage { +pub fn tokens( + values: impl IntoIterator + Clone, +) -> impl BuildStorage { orml_tokens::GenesisConfig:: { balances: default_accounts() .into_iter() @@ -53,24 +58,30 @@ pub fn tokens(values: Vec<(CurrencyId, Balance)>) -> impl BuildStora } } -pub fn assets(currency_ids: Vec<&dyn CurrencyInfo>) -> impl BuildStorage { +pub fn assets<'a, T: Runtime>( + currency_ids: impl IntoIterator, +) -> impl BuildStorage { orml_asset_registry::module::GenesisConfig:: { assets: currency_ids .into_iter() - .map(|currency_id| (currency_id.id(), currency_id.metadata().encode())) + .map(|(currency_id, metadata)| (currency_id, metadata.encode())) .collect(), last_asset_id: Default::default(), // It seems deprecated } } -pub fn council_members(members: Vec) -> impl BuildStorage { +pub fn council_members( + members: impl IntoIterator, +) -> impl BuildStorage { pallet_collective::GenesisConfig:: { phantom: Default::default(), members: members.into_iter().map(|acc| acc.id()).collect(), } } -pub fn invulnerables(invulnerables: Vec) -> impl BuildStorage { +pub fn invulnerables( + invulnerables: impl IntoIterator, +) -> impl BuildStorage { pallet_collator_selection::GenesisConfig:: { invulnerables: invulnerables.into_iter().map(|acc| acc.id()).collect(), candidacy_bond: cfg_primitives::MILLI_CFG, @@ -87,7 +98,9 @@ pub fn session_keys() -> impl BuildStorage { } } -pub fn block_rewards(collators: Vec) -> impl BuildStorage { +pub fn block_rewards( + collators: impl IntoIterator, +) -> impl BuildStorage { pallet_block_rewards::GenesisConfig:: { collators: collators.into_iter().map(|acc| acc.id()).collect(), collator_reward: (1000 * cfg_primitives::CFG).into(), diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index 97c788071b..cc8e270f2e 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -1,14 +1,18 @@ +use cfg_primitives::AccountId; +use cfg_types::tokens::{AssetMetadata, CrossChainTransferability, CustomMetadata}; use frame_support::{assert_ok, traits::OriginTrait}; use polkadot_parachain_primitives::primitives::Id; use staging_xcm::{ prelude::XCM_VERSION, v4::{Junction, Location}, + VersionedLocation, }; use crate::generic::{ config::Runtime, env::{Blocks, Env}, envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, + utils::currency::default_metadata, }; pub fn setup_xcm(env: &mut FudgeEnv) { @@ -67,3 +71,31 @@ pub fn setup_xcm(env: &mut FudgeEnv) { env.pass(Blocks::ByNumber(1)); } + +pub fn account_location(account_id: AccountId, para_id: u32) -> Box { + Box::new( + Location::new( + 1, + [ + Junction::Parachain(para_id), + Junction::AccountId32 { + network: None, + id: account_id.into(), + }, + ], + ) + .into(), + ) +} + +pub fn transferable_metadata(decimals: u32) -> AssetMetadata { + AssetMetadata { + decimals, + location: Some(Location::new(1, Junction::Parachain(T::FudgeHandle::PARA_ID)).into()), + additional: CustomMetadata { + transferability: CrossChainTransferability::xcm_with_fees(0), + ..Default::default() + }, + ..default_metadata() + } +} diff --git a/runtime/integration-tests/src/utils/accounts.rs b/runtime/integration-tests/src/utils/accounts.rs index 463e962f58..0b38d5f9de 100644 --- a/runtime/integration-tests/src/utils/accounts.rs +++ b/runtime/integration-tests/src/utils/accounts.rs @@ -40,10 +40,6 @@ impl Keyring { self.to_account_id() } - pub fn bytes(self) -> [u8; 32] { - self.public().0 - } - pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } From e9174c958081697e4874f9c70fff45e6138be52b Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 11 Jun 2024 19:50:48 +0200 Subject: [PATCH 03/21] fix tests --- runtime/integration-tests/src/generic/cases/xtransfers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index 8886640755..ee7467a9b8 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -134,7 +134,7 @@ fn foreign_to_native_tokens() { )); assert_eq!( - orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Bob.id()), + orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Alice.id()), xnative.val(INITIAL) - xnative.val(TRANSFER) ); }); @@ -143,7 +143,7 @@ fn foreign_to_native_tokens() { env.sibling_state_mut(|| { assert_eq!( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), + pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), cfg(TRANSFER) ); }); From 57908e9b09ca266747a013ebc5c6668158503d8a Mon Sep 17 00:00:00 2001 From: lemunozm Date: Wed, 12 Jun 2024 17:52:20 +0200 Subject: [PATCH 04/21] transfer relay tests --- libs/primitives/src/lib.rs | 6 +- runtime/altair/src/xcm.rs | 22 +-- runtime/centrifuge/src/xcm.rs | 22 +-- runtime/common/src/xcm.rs | 14 +- runtime/development/src/xcm.rs | 21 +- .../src/generic/cases/liquidity_pools.rs | 186 ------------------ .../src/generic/cases/xtransfers.rs | 109 ++++++++-- .../src/generic/envs/fudge_env.rs | 2 + .../src/generic/envs/fudge_env/handle.rs | 2 - .../src/generic/utils/genesis.rs | 6 +- .../src/generic/utils/xcm.rs | 114 +++++++---- runtime/integration-tests/src/utils/mod.rs | 64 ++++++ 12 files changed, 272 insertions(+), 296 deletions(-) diff --git a/libs/primitives/src/lib.rs b/libs/primitives/src/lib.rs index 4bc2b25e6d..d92a92bc3d 100644 --- a/libs/primitives/src/lib.rs +++ b/libs/primitives/src/lib.rs @@ -283,6 +283,8 @@ pub mod constants { /// The maximum number of pool fees per pool fee bucket pub const MAX_POOL_FEES_PER_BUCKET: u32 = 100; + + pub const NATIVE_KEY: &[u8] = &[0, 1]; } /// Listing of parachains we integrate with. @@ -301,7 +303,7 @@ pub mod parachains { pub mod altair { pub const ID: u32 = 2088; - pub const AIR_KEY: &[u8] = &[0, 1]; + pub const AIR_KEY: &[u8] = crate::NATIVE_KEY; } } @@ -313,7 +315,7 @@ pub mod parachains { pub mod centrifuge { pub const ID: u32 = 2031; - pub const CFG_KEY: &[u8] = &[0, 1]; + pub const CFG_KEY: &[u8] = crate::NATIVE_KEY; } } diff --git a/runtime/altair/src/xcm.rs b/runtime/altair/src/xcm.rs index ab0c2e231b..379a0606e2 100644 --- a/runtime/altair/src/xcm.rs +++ b/runtime/altair/src/xcm.rs @@ -10,10 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{ - parachains, - types::{EnsureRootOr, HalfOfCouncil}, -}; +use cfg_primitives::types::{EnsureRootOr, HalfOfCouncil}; use cfg_types::tokens::CurrencyId; use frame_support::{ parameter_types, @@ -27,10 +24,9 @@ use pallet_xcm::XcmPassthrough; use runtime_common::{ transfer_filter::PreXcmTransfer, xcm::{ - general_key, AccountIdToLocation, Barrier, FixedConversionRateProvider, + AccountIdToLocation, Barrier, CanonicalNativePerSecond, FixedConversionRateProvider, LocalOriginToLocation, ToTreasury, }, - xcm_fees::native_per_second, }; use sp_core::ConstU32; use staging_xcm::{ @@ -88,25 +84,13 @@ impl staging_xcm_executor::Config for XcmConfig { /// else the xcm executor won't know how to charge fees for a transfer of said /// token. pub type Trader = ( - FixedRateOfFungible>, + FixedRateOfFungible>, AssetRegistryTrader< FixedRateAssetRegistryTrader>, ToTreasury, >, ); -parameter_types! { - // Canonical location: https://github.com/paritytech/polkadot/pull/4470 - pub CanonicalAirPerSecond: (AssetId, u128, u128) = ( - Location::new( - 0, - general_key(parachains::kusama::altair::AIR_KEY) - ).into(), - native_per_second(), - 0, - ); -} - /// Means for transacting the fungibles assets of this parachain. pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation diff --git a/runtime/centrifuge/src/xcm.rs b/runtime/centrifuge/src/xcm.rs index cd1da395a4..ef74d41fe1 100644 --- a/runtime/centrifuge/src/xcm.rs +++ b/runtime/centrifuge/src/xcm.rs @@ -10,10 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{ - parachains, - types::{EnsureRootOr, HalfOfCouncil}, -}; +use cfg_primitives::types::{EnsureRootOr, HalfOfCouncil}; use cfg_traits::TryConvert; use cfg_types::{tokens::CurrencyId, EVMChainId}; use frame_support::{ @@ -28,10 +25,9 @@ use pallet_xcm::XcmPassthrough; use runtime_common::{ transfer_filter::PreXcmTransfer, xcm::{ - general_key, AccountIdToLocation, Barrier, FixedConversionRateProvider, + AccountIdToLocation, Barrier, CanonicalNativePerSecond, FixedConversionRateProvider, LocalOriginToLocation, LpInstanceRelayer, ToTreasury, }, - xcm_fees::native_per_second, }; use sp_core::ConstU32; use staging_xcm::{ @@ -89,25 +85,13 @@ impl staging_xcm_executor::Config for XcmConfig { /// else the xcm executor won't know how to charge fees for a transfer of said /// token. pub type Trader = ( - FixedRateOfFungible>, + FixedRateOfFungible>, AssetRegistryTrader< FixedRateAssetRegistryTrader>, ToTreasury, >, ); -parameter_types! { - // Canonical location: https://github.com/paritytech/polkadot/pull/4470 - pub CanonicalCfgPerSecond: (AssetId, u128, u128) = ( - Location::new( - 0, - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ).into(), - native_per_second(), - 0, - ); -} - /// Means for transacting the fungibles assets of this parachain. pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation diff --git a/runtime/common/src/xcm.rs b/runtime/common/src/xcm.rs index e4e0a8dce8..c44f757c33 100644 --- a/runtime/common/src/xcm.rs +++ b/runtime/common/src/xcm.rs @@ -36,7 +36,7 @@ use staging_xcm_builder::{ TakeWeightCredit, }; -use crate::xcm_fees::default_per_second; +use crate::xcm_fees::{default_per_second, native_per_second}; /// Our FixedConversionRateProvider, used to charge XCM-related fees for /// tokens registered in the asset registry that were not already handled by @@ -71,6 +71,18 @@ pub fn general_key(data: &[u8]) -> staging_xcm::latest::Junction { } } +frame_support::parameter_types! { + // Canonical location: https://github.com/paritytech/polkadot/pull/4470 + pub CanonicalNativePerSecond: (AssetId, u128, u128) = ( + Location::new( + 0, + general_key(cfg_primitives::NATIVE_KEY), + ).into(), + native_per_second(), + 0, + ); +} + /// How we convert an `[AccountId]` into an XCM Location pub struct AccountIdToLocation; impl> Convert for AccountIdToLocation { diff --git a/runtime/development/src/xcm.rs b/runtime/development/src/xcm.rs index b9efe50bed..ac260246f0 100644 --- a/runtime/development/src/xcm.rs +++ b/runtime/development/src/xcm.rs @@ -9,10 +9,7 @@ // 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 cfg_primitives::{ - parachains, - types::{EnsureRootOr, HalfOfCouncil}, -}; +use cfg_primitives::types::{EnsureRootOr, HalfOfCouncil}; use cfg_traits::TryConvert; use cfg_types::{tokens::CurrencyId, EVMChainId}; use frame_support::{ @@ -27,10 +24,9 @@ use pallet_xcm::XcmPassthrough; use runtime_common::{ transfer_filter::PreXcmTransfer, xcm::{ - general_key, AccountIdToLocation, Barrier, FixedConversionRateProvider, + AccountIdToLocation, Barrier, CanonicalNativePerSecond, FixedConversionRateProvider, LocalOriginToLocation, LpInstanceRelayer, ToTreasury, }, - xcm_fees::native_per_second, }; use sp_core::ConstU32; use staging_xcm::{ @@ -95,19 +91,6 @@ pub type Trader = ( >, ); -parameter_types! { - // Canonical location: https://github.com/paritytech/polkadot/pull/4470 - pub CanonicalNativePerSecond: (AssetId, u128, u128) = ( - Location::new( - 0, - general_key(parachains::kusama::altair::AIR_KEY), - ).into(), - native_per_second(), - 0, - ); - -} - /// Means for transacting the fungibles assets of this parachain. pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 3cb300a6f3..04d8e67cdb 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -5065,138 +5065,6 @@ mod altair { use utils::*; - mod transfers { - use super::*; - - 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(), - as frame_system::Config>::Lookup::unlookup( - Keyring::Alice.id() - ), - transfer_amount * 2, - ) - ); - - assert_ok!( - pallet_xcm::Pallet::>::force_xcm_version( - as frame_system::Config>::RuntimeOrigin::root(), - Box::new(Location::new( - 0, - 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(2)); - - env.parachain_state(|| { - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &Keyring::Bob.into()), - 1991963000000 // Comes from `transfer_amount - fee(meta.decimals)` with noise - ); - }); - } - - #[test_runtimes([altair])] - fn transfer_ksm_to_and_from_relay_chain() { - let mut env = FudgeEnv::::default(); - - let transfer_amount: Balance = ksm(2); - let currency_id = CurrencyId::ForeignAsset(3001); - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000, - location: Some(VersionedLocation::V4(Location::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_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::new(1, Junctions::Here)), - XCM_VERSION, - )); - - assert_ok!(orml_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Bob.into()).into(), - currency_id, - ksm(1), - Box::new( - Location::new( - 1, - Junction::AccountId32 { - id: Keyring::Bob.into(), - network: None, - } - ) - .into() - ), - WeightLimit::Limited(4_000_000_000.into()) - )); - }); - - env.pass(Blocks::ByNumber(2)); - - env.relay_state_mut(|| { - assert_eq!( - pallet_balances::Pallet::>::free_balance( - &Keyring::Bob.into() - ), - 999989698923 - ); - }); - } - } - mod asset_registry { use super::*; @@ -6762,58 +6630,4 @@ mod centrifuge { }); } } - - mod transfers { - use super::*; - #[test_runtimes([centrifuge])] - fn transfer_dot_to_and_from_relay_chain() { - let mut env = FudgeEnv::::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_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::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( - Location::new( - 1, - 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(2)); - - env.relay_state_mut(|| { - assert_eq!( - pallet_balances::Pallet::>::free_balance( - &Keyring::Alice.into() - ), - 79857365914 - ); - }); - } - } } diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index ee7467a9b8..077b808aef 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -1,13 +1,13 @@ -use cfg_types::tokens::CurrencyId; +use cfg_types::tokens::{AssetMetadata, CurrencyId}; use frame_support::{assert_ok, dispatch::RawOrigin}; use orml_traits::MultiCurrency; -use staging_xcm::v4::WeightLimit; +use staging_xcm::v4::{prelude::XCM_VERSION, Junction::*, Junctions::Here, Location, WeightLimit}; use crate::{ generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, utils::{ currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, @@ -15,14 +15,16 @@ use crate::{ xcm::{account_location, setup_xcm, transferable_metadata}, }, }, - utils::accounts::Keyring, + utils::{accounts::Keyring, approx::Approximate}, }; const INITIAL: u32 = 100; -const TRANSFER: u32 = 80; +const TRANSFER: u32 = 20; + +type Relay = FudgeRelayRuntime; #[test_runtimes(all)] -fn foreign_to_foreign_tokens() { +fn para_to_sibling_with_foreign_to_foreign_tokens() { let curr = CustomCurrency(CurrencyId::ForeignAsset(1), transferable_metadata::(6)); let mut env = FudgeEnv::::from_storage( @@ -43,7 +45,7 @@ fn foreign_to_foreign_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), curr.id(), curr.val(TRANSFER), - account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), + account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -64,7 +66,7 @@ fn foreign_to_foreign_tokens() { } #[test_runtimes(all)] -fn native_to_foreign_tokens() { +fn para_to_sibling_with_native_to_foreign_tokens() { let metadata = transferable_metadata::(18); let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); @@ -86,7 +88,7 @@ fn native_to_foreign_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), CurrencyId::Native, cfg(TRANSFER), - account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), + account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -107,7 +109,7 @@ fn native_to_foreign_tokens() { } #[test_runtimes(all)] -fn foreign_to_native_tokens() { +fn para_to_sibling_with_foreign_to_native_tokens() { let metadata = transferable_metadata::(18); let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); @@ -129,7 +131,7 @@ fn foreign_to_native_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), xnative.id(), xnative.val(TRANSFER), - account_location(Keyring::Bob.id(), T::FudgeHandle::SIBLING_ID), + account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -148,3 +150,88 @@ fn foreign_to_native_tokens() { ); }); } + +#[test_runtimes(all)] +fn from_to_relay_using_relay_native_tokens() { + let xrelay = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + location: Some(Location::parent().into()), + ..transferable_metadata::(10) + }, + ); + + let mut env = FudgeEnv::::from_storage( + Genesis::default() + .add(genesis::balances::>(xrelay.val(INITIAL))) + .storage(), + Genesis::default() + .add(genesis::assets::([(xrelay.id(), &xrelay.metadata())])) + .storage(), + Default::default(), + ); + + // From Relay to Parachain + + env.relay_state_mut(|| { + assert_ok!(pallet_xcm::Pallet::>::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), + XCM_VERSION, + )); + + assert_ok!(pallet_xcm::Pallet::>::reserve_transfer_assets( + RawOrigin::Signed(Keyring::Alice.id()).into(), + Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), + account_location(0, None, Keyring::Bob.id()), + Box::new((Here, xrelay.val(TRANSFER)).into()), + 0, + )); + + assert_eq!( + pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), + (xrelay.val(INITIAL) - xrelay.val(TRANSFER)).approx(0.01) + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.parachain_state_mut(|| { + assert_eq!( + orml_tokens::Pallet::::free_balance(xrelay.id(), &Keyring::Bob.id()), + xrelay.val(TRANSFER) + ); + }); + + // From Parachain to Relay + + env.parachain_state_mut(|| { + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::parent()), + XCM_VERSION, + )); + + assert_ok!(orml_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Bob.id()).into(), + xrelay.id(), + xrelay.val(TRANSFER / 2), + account_location(1, None, Keyring::Alice.id()), + WeightLimit::Unlimited, + )); + + assert_eq!( + orml_tokens::Pallet::::free_balance(xrelay.id(), &Keyring::Bob.id()), + (xrelay.val(TRANSFER) - xrelay.val(TRANSFER / 2)).approx(0.01) + ); + }); + + env.pass(Blocks::ByNumber(2)); + + env.relay_state_mut(|| { + assert_eq!( + pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), + (xrelay.val(INITIAL) - xrelay.val(TRANSFER) + xrelay.val(TRANSFER / 2)).approx(0.01) + ); + }); +} diff --git a/runtime/integration-tests/src/generic/envs/fudge_env.rs b/runtime/integration-tests/src/generic/envs/fudge_env.rs index ffae30929b..7c6492d446 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env.rs @@ -48,6 +48,8 @@ impl Env for FudgeEnv { parachain_storage: Storage, sibling_storage: Storage, ) -> Self { + crate::utils::logs::init_logs(); + let mut handle = T::FudgeHandle::new(relay_storage, parachain_storage, sibling_storage); handle.evolve(); 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 0e5321df5e..5bb99eafc2 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs @@ -146,8 +146,6 @@ pub trait FudgeHandle { storage: Storage, session_keys: ::Keys, ) -> RelaychainBuilder { - crate::utils::logs::init_logs(); - sp_tracing::enter_span!(sp_tracing::Level::INFO, "Relay - StartUp"); let code = Self::RELAY_CODE.expect("ESSENTIAL: WASM is built."); diff --git a/runtime/integration-tests/src/generic/utils/genesis.rs b/runtime/integration-tests/src/generic/utils/genesis.rs index a87b470184..87996e34d8 100644 --- a/runtime/integration-tests/src/generic/utils/genesis.rs +++ b/runtime/integration-tests/src/generic/utils/genesis.rs @@ -1,7 +1,7 @@ //! PLEASE be as much generic as possible because no domain or use cases are //! considered at this level. -use cfg_primitives::Balance; +use cfg_primitives::{AccountId, Balance}; use cfg_types::{ fixed_point::Rate, tokens::{AssetMetadata, CurrencyId}, @@ -31,7 +31,9 @@ impl Genesis { } } -pub fn balances(balance: Balance) -> impl BuildStorage { +pub fn balances>( + balance: Balance, +) -> impl BuildStorage { pallet_balances::GenesisConfig:: { balances: default_accounts() .into_iter() diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index cc8e270f2e..a2373fb7e2 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -1,10 +1,10 @@ use cfg_primitives::AccountId; use cfg_types::tokens::{AssetMetadata, CrossChainTransferability, CustomMetadata}; -use frame_support::{assert_ok, traits::OriginTrait}; +use frame_support::{assert_ok, dispatch::RawOrigin}; use polkadot_parachain_primitives::primitives::Id; use staging_xcm::{ prelude::XCM_VERSION, - v4::{Junction, Location}, + v4::{Junction::*, Location}, VersionedLocation, }; @@ -17,44 +17,40 @@ use crate::generic::{ pub fn setup_xcm(env: &mut FudgeEnv) { env.parachain_state_mut(|| { - // Set the XCM version used when sending XCM messages to sibling. + // Gives sibling where to find the parachain assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::new( - 1, - Junction::Parachain(T::FudgeHandle::SIBLING_ID), - )), + RawOrigin::Root.into(), + Box::new(Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID))), XCM_VERSION, )); }); env.sibling_state_mut(|| { - // Set the XCM version used when sending XCM messages to parachain. + // Gives parachain where to find the sibling assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::new( - 1, - Junction::Parachain(T::FudgeHandle::PARA_ID), - )), + RawOrigin::Root.into(), + Box::new(Location::new(1, Parachain(T::FudgeHandle::PARA_ID))), XCM_VERSION, )); }); env.relay_state_mut(|| { + // Enable para -> sibling comunication though relay assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< FudgeRelayRuntime, >::force_open_hrmp_channel( - as frame_system::Config>::RuntimeOrigin::root(), + RawOrigin::Root.into(), Id::from(T::FudgeHandle::PARA_ID), Id::from(T::FudgeHandle::SIBLING_ID), 10, 1024, )); + // Enable sibling -> para comunication though relay assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< FudgeRelayRuntime, >::force_open_hrmp_channel( - as frame_system::Config>::RuntimeOrigin::root(), + RawOrigin::Root.into(), Id::from(T::FudgeHandle::SIBLING_ID), Id::from(T::FudgeHandle::PARA_ID), 10, @@ -63,35 +59,83 @@ pub fn setup_xcm(env: &mut FudgeEnv) { assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< FudgeRelayRuntime, - >::force_process_hrmp_open( - as frame_system::Config>::RuntimeOrigin::root(), - 2, - )); + >::force_process_hrmp_open(RawOrigin::Root.into(), 2)); }); env.pass(Blocks::ByNumber(1)); } -pub fn account_location(account_id: AccountId, para_id: u32) -> Box { - Box::new( - Location::new( - 1, - [ - Junction::Parachain(para_id), - Junction::AccountId32 { - network: None, - id: account_id.into(), - }, - ], - ) - .into(), - ) +/* +pub fn enable_relay_to_para_communication() { + env.relay_state_mut(|| { + assert_ok!( + pallet_xcm::Pallet::>::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), + XCM_VERSION, + ) + ); + }); +} + +pub fn enable_para_to_relay_communication() { + env.parachain_state_mut(|| { + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::parent()), + XCM_VERSION, + )); + }); +} + +pub fn enable_para_to_sibling_communication() { + env.parachain_state_mut(|| { + assert_ok!(pallet_xcm::Pallet::::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID))), + XCM_VERSION, + )); + }); + + env.relay_state_mut(|| { + // Enable para -> sibling comunication though relay + assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< + FudgeRelayRuntime, + >::force_open_hrmp_channel( + RawOrigin::Root.into(), + Id::from(T::FudgeHandle::PARA_ID), + Id::from(T::FudgeHandle::SIBLING_ID), + 10, + 1024, + )); + + assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< + FudgeRelayRuntime, + >::force_process_hrmp_open(RawOrigin::Root.into(), 1)); + }); +} +*/ + +pub fn account_location( + parents: u8, + para_id: Option, + account_id: AccountId, +) -> Box { + let account = AccountId32 { + network: None, + id: account_id.into(), + }; + + Box::new(VersionedLocation::V4(match para_id { + Some(para_id) => Location::new(parents, [Parachain(para_id), account]), + None => Location::new(parents, account), + })) } pub fn transferable_metadata(decimals: u32) -> AssetMetadata { AssetMetadata { decimals, - location: Some(Location::new(1, Junction::Parachain(T::FudgeHandle::PARA_ID)).into()), + location: Some(Location::new(1, Parachain(T::FudgeHandle::PARA_ID)).into()), additional: CustomMetadata { transferability: CrossChainTransferability::xcm_with_fees(0), ..Default::default() diff --git a/runtime/integration-tests/src/utils/mod.rs b/runtime/integration-tests/src/utils/mod.rs index a6da19e701..3ee465c7a6 100644 --- a/runtime/integration-tests/src/utils/mod.rs +++ b/runtime/integration-tests/src/utils/mod.rs @@ -18,3 +18,67 @@ pub mod orml_asset_registry { // we reexport it again here pub use orml_asset_registry::module::*; } + +pub mod approx { + use std::fmt; + + use cfg_primitives::Balance; + + #[derive(Clone)] + pub struct Approximation { + value: Balance, + offset: Balance, + is_positive: bool, + } + + impl PartialEq for Balance { + fn eq(&self, ap: &Approximation) -> bool { + match ap.is_positive { + true => *self <= ap.value && *self + ap.offset >= ap.value, + false => *self >= ap.value && *self - ap.offset <= ap.value, + } + } + } + + impl fmt::Debug for Approximation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (from, to) = match self.is_positive { + true => (self.value - self.offset, self.value), + false => (self.value, self.value + self.offset), + }; + + write!(f, "Approximation: [{}, {}]", from, to) + } + } + + /// Allow to compare `Balance` values with approximated values: + pub trait Approximate { + fn approx(&self, variation: f64) -> Approximation; + } + + impl Approximate for Balance { + fn approx(&self, variation: f64) -> Approximation { + let offset = match variation >= 0.0 { + true => (*self as f64 * variation) as Balance, + false => (*self as f64 * -variation) as Balance, + }; + + Approximation { + value: *self, + offset, + is_positive: variation >= 0.0, + } + } + } + + #[test] + fn approximations() { + assert_eq!(1000u128, 996.approx(-0.01)); + assert_eq!(1000u128, 1004.approx(0.01)); + assert_eq!(1000u128, 1500.approx(0.5)); + + assert_ne!(1000u128, 996.approx(0.01)); + assert_ne!(1000u128, 1004.approx(-0.01)); + assert_ne!(1000u128, 1500.approx(0.1)); + } +} From 1770f1108eb09923da779fc46af9f502d8f89da1 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 13 Jun 2024 08:43:43 +0200 Subject: [PATCH 05/21] polish and minor cleans --- .../src/generic/cases/liquidity_pools.rs | 77 +++---------------- .../src/generic/cases/proxy.rs | 47 +++-------- .../src/generic/cases/xtransfers.rs | 28 +++---- .../src/generic/utils/xcm.rs | 60 ++------------- 4 files changed, 35 insertions(+), 177 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 04d8e67cdb..20c8e0a5eb 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -70,7 +70,7 @@ use crate::{ envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, utils::{ democracy::execute_via_democracy, evm::mint_balance_into_derived_account, genesis, - genesis::Genesis, xcm::setup_xcm, + genesis::Genesis, xcm::enable_para_to_sibling_communication, }, }, utils::{accounts::Keyring, orml_asset_registry}, @@ -424,8 +424,6 @@ mod development { } pub fn setup_test(env: &mut FudgeEnv) { - setup_xcm(env); - env.parachain_state_mut(|| { register_ausd::(); register_glmr::(); @@ -5385,7 +5383,7 @@ mod centrifuge { )); } - pub fn register_usdc() { + pub fn register_usdc(para_id: u32) { let meta: AssetMetadata = AssetMetadata { decimals: 6, name: BoundedVec::default(), @@ -5393,11 +5391,7 @@ mod centrifuge { existential_deposit: 1_000, location: Some(VersionedLocation::V4(Location::new( 1, - [ - Junction::Parachain(1000), - Junction::PalletInstance(50), - Junction::GeneralIndex(1337), - ], + Junction::Parachain(para_id), ))), additional: CustomMetadata { transferability: CrossChainTransferability::Xcm(Default::default()), @@ -5969,7 +5963,7 @@ mod centrifuge { // Restrict USDC local env.parachain_state_mut(|| { - register_usdc::(); + register_usdc::(1000); let pre_transfer_alice = orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.to_account_id()); @@ -6177,10 +6171,8 @@ mod centrifuge { .storage(), ); - setup_xcm(&mut env); - env.parachain_state_mut(|| { - register_usdc::(); + register_usdc::(T::FudgeHandle::SIBLING_ID); register_lp_eth_usdc::(); assert_ok!(orml_tokens::Pallet::::set_balance( @@ -6276,7 +6268,7 @@ mod centrifuge { ); env.parachain_state_mut(|| { - register_usdc::(); + register_usdc::(1000); let pre_transfer_alice = orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.to_account_id()); @@ -6334,53 +6326,17 @@ mod centrifuge { #[test_runtimes([centrifuge])] fn restrict_usdc_xcm_transfer() { - let mut env = FudgeEnv::::from_storage( - paras::GenesisConfig::> { - _config: Default::default(), - paras: vec![( - 1000.into(), - ParaGenesisArgs { - genesis_head: Default::default(), - validation_code: ValidationCode::from(vec![0, 1, 2, 3]), - para_kind: ParaKind::Parachain, - }, - )], - } - .build_storage() - .unwrap(), + let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(10))) + .add(genesis::tokens::([(USDC, usdc(3_000))])) .storage(), - Default::default(), ); - // Configuring XCM in this test fails because the Hrmp - // configuration is not applied. We force the application here, - // but we should configure correctly this because something is off. - env.relay_state_mut(|| { - polkadot_runtime_parachains::configuration::Pallet::>::force_set_active_config( - crate::generic::envs::fudge_env::handle::hrmp_host_config() - ); - }); - - setup_xcm(&mut env); - - setup_usdc_xcm(&mut env); - - env.sibling_state_mut(|| { - register_usdc::(); - }); + enable_para_to_sibling_communication::(&mut env); env.parachain_state_mut(|| { - register_usdc::(); - - let alice_initial_usdc = usdc(3_000); - - assert_ok!(orml_tokens::Pallet::::mint_into( - USDC, - &Keyring::Alice.into(), - alice_initial_usdc - )); + register_usdc::(T::FudgeHandle::SIBLING_ID); assert_ok!( pallet_transfer_allowlist::Pallet::::add_transfer_allowance( @@ -6443,20 +6399,7 @@ mod centrifuge { ), WeightLimit::Unlimited, )); - - assert_eq!( - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.into()), - alice_initial_usdc - usdc(1_000), - ); }); - - // NOTE - we cannot confirm that the Alice account present on the - // sibling receives this transfer since the orml_xtokens pallet - // sends a message to parachain 1000 (the parachain of the USDC - // currency) which in turn should send a message to the sibling. - // Since parachain 1000 is just a dummy added in the paras - // genesis config and not an actual sibling with a runtime, the - // transfer does not take place. } #[test_runtimes([centrifuge])] diff --git a/runtime/integration-tests/src/generic/cases/proxy.rs b/runtime/integration-tests/src/generic/cases/proxy.rs index fdd1781e28..509288e2f2 100644 --- a/runtime/integration-tests/src/generic/cases/proxy.rs +++ b/runtime/integration-tests/src/generic/cases/proxy.rs @@ -21,7 +21,6 @@ use crate::{ self, currency::{cfg, register_currency, usd6, CurrencyInfo, Usd6}, genesis::{self, Genesis}, - xcm::setup_xcm, }, }, utils::accounts::Keyring, @@ -33,14 +32,13 @@ const TO: Keyring = Keyring::Bob; const FOR_FEES: Balance = cfg(1); const TRANSFER_AMOUNT: Balance = usd6(100); +const INITIAL: Balance = usd6(1000) + TRANSFER_AMOUNT; fn configure_proxy_and_transfer(proxy_type: T::ProxyType) -> DispatchResult { let env = RuntimeEnv::::from_parachain_storage( Genesis::default() - .add(genesis::balances::( - T::ExistentialDeposit::get() + FOR_FEES, - )) - .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) + .add(genesis::balances::(FOR_FEES)) + .add(genesis::tokens::(vec![(Usd6.id(), INITIAL)])) .storage(), ); @@ -57,45 +55,20 @@ fn configure_proxy_and_transfer(proxy_type: T::ProxyType) -> Dispatc fn configure_proxy_and_x_transfer( proxy_type: T::ProxyType, ) -> DispatchResult { + let curr = CustomCurrency(Usd6.id(), transferable_metadata::(6)); + let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() - .add(genesis::balances::( - T::ExistentialDeposit::get() + FOR_FEES, - )) - .add(genesis::tokens::(vec![(Usd6.id(), Usd6.ed())])) + .add(genesis::balances::(FOR_FEES)) + .add(genesis::tokens::(vec![(curr.id(), INITIAL)])) + .add(genesis::assets::(vec![(curr.id(), curr.metadata())])) .storage(), ); - setup_xcm(&mut env); - - env.parachain_state_mut(|| { - register_currency::(Usd6, |meta| { - meta.location = Some(VersionedLocation::V4(Location::new( - 1, - Parachain(T::FudgeHandle::SIBLING_ID), - ))); - meta.additional.transferability = CrossChainTransferability::Xcm(XcmMetadata { - fee_per_second: Some(1_000), - }); - }); - }); - let call = pallet_restricted_xtokens::Call::transfer { currency_id: Usd6.id(), amount: TRANSFER_AMOUNT, - dest: Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - id: TO.into(), - network: None, - }, - ], - ) - .into(), - ), + dest: account_location(1, T::FudgeHandle::SIBLING_ID, TO.id()), dest_weight_limit: WeightLimit::Unlimited, } .into(); @@ -109,8 +82,6 @@ fn configure_proxy_and_call( call: T::RuntimeCallExt, ) -> DispatchResult { env.parachain_state_mut(|| { - utils::give_tokens::(FROM.id(), Usd6.id(), TRANSFER_AMOUNT); - // Register PROXY as proxy of FROM pallet_proxy::Pallet::::add_proxy( RawOrigin::Signed(FROM.id()).into(), diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index 077b808aef..9e14b17a35 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -1,7 +1,7 @@ use cfg_types::tokens::{AssetMetadata, CurrencyId}; use frame_support::{assert_ok, dispatch::RawOrigin}; use orml_traits::MultiCurrency; -use staging_xcm::v4::{prelude::XCM_VERSION, Junction::*, Junctions::Here, Location, WeightLimit}; +use staging_xcm::v4::{Junction::*, Junctions::Here, Location, WeightLimit}; use crate::{ generic::{ @@ -12,7 +12,11 @@ use crate::{ currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, genesis::Genesis, - xcm::{account_location, setup_xcm, transferable_metadata}, + xcm::{ + account_location, enable_para_to_relay_communication, + enable_para_to_sibling_communication, enable_relay_to_para_communication, + transferable_metadata, + }, }, }, utils::{accounts::Keyring, approx::Approximate}, @@ -38,7 +42,7 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { .storage(), ); - setup_xcm(&mut env); + enable_para_to_sibling_communication::(&mut env); env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( @@ -81,7 +85,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { .storage(), ); - setup_xcm(&mut env); + enable_para_to_sibling_communication::(&mut env); env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( @@ -124,7 +128,7 @@ fn para_to_sibling_with_foreign_to_native_tokens() { .storage(), ); - setup_xcm(&mut env); + enable_para_to_sibling_communication::(&mut env); env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( @@ -172,14 +176,9 @@ fn from_to_relay_using_relay_native_tokens() { ); // From Relay to Parachain + enable_relay_to_para_communication::(&mut env); env.relay_state_mut(|| { - assert_ok!(pallet_xcm::Pallet::>::force_xcm_version( - RawOrigin::Root.into(), - Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), - XCM_VERSION, - )); - assert_ok!(pallet_xcm::Pallet::>::reserve_transfer_assets( RawOrigin::Signed(Keyring::Alice.id()).into(), Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), @@ -204,14 +203,9 @@ fn from_to_relay_using_relay_native_tokens() { }); // From Parachain to Relay + enable_para_to_relay_communication::(&mut env); env.parachain_state_mut(|| { - assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - RawOrigin::Root.into(), - Box::new(Location::parent()), - XCM_VERSION, - )); - assert_ok!(orml_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Bob.id()).into(), xrelay.id(), diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index a2373fb7e2..dbb82a13e6 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -15,58 +15,7 @@ use crate::generic::{ utils::currency::default_metadata, }; -pub fn setup_xcm(env: &mut FudgeEnv) { - env.parachain_state_mut(|| { - // Gives sibling where to find the parachain - assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - RawOrigin::Root.into(), - Box::new(Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID))), - XCM_VERSION, - )); - }); - - env.sibling_state_mut(|| { - // Gives parachain where to find the sibling - assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - RawOrigin::Root.into(), - Box::new(Location::new(1, Parachain(T::FudgeHandle::PARA_ID))), - XCM_VERSION, - )); - }); - - env.relay_state_mut(|| { - // Enable para -> sibling comunication though relay - assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< - FudgeRelayRuntime, - >::force_open_hrmp_channel( - RawOrigin::Root.into(), - Id::from(T::FudgeHandle::PARA_ID), - Id::from(T::FudgeHandle::SIBLING_ID), - 10, - 1024, - )); - - // Enable sibling -> para comunication though relay - assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< - FudgeRelayRuntime, - >::force_open_hrmp_channel( - RawOrigin::Root.into(), - 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(RawOrigin::Root.into(), 2)); - }); - - env.pass(Blocks::ByNumber(1)); -} - -/* -pub fn enable_relay_to_para_communication() { +pub fn enable_relay_to_para_communication(env: &mut FudgeEnv) { env.relay_state_mut(|| { assert_ok!( pallet_xcm::Pallet::>::force_xcm_version( @@ -78,7 +27,7 @@ pub fn enable_relay_to_para_communication() { }); } -pub fn enable_para_to_relay_communication() { +pub fn enable_para_to_relay_communication(env: &mut FudgeEnv) { env.parachain_state_mut(|| { assert_ok!(pallet_xcm::Pallet::::force_xcm_version( RawOrigin::Root.into(), @@ -88,7 +37,7 @@ pub fn enable_para_to_relay_communication() { }); } -pub fn enable_para_to_sibling_communication() { +pub fn enable_para_to_sibling_communication(env: &mut FudgeEnv) { env.parachain_state_mut(|| { assert_ok!(pallet_xcm::Pallet::::force_xcm_version( RawOrigin::Root.into(), @@ -113,8 +62,9 @@ pub fn enable_para_to_sibling_communication() { FudgeRelayRuntime, >::force_process_hrmp_open(RawOrigin::Root.into(), 1)); }); + + env.pass(Blocks::ByNumber(1)); } -*/ pub fn account_location( parents: u8, From 5b41f5ec8cc5435b8d0fc1391be77cda81316cbf Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 13 Jun 2024 11:03:16 +0200 Subject: [PATCH 06/21] fixes --- .../src/generic/cases/liquidity_pools.rs | 9 +-- .../src/generic/cases/proxy.rs | 30 +++---- .../src/generic/cases/xtransfers.rs | 78 ++++++++++--------- .../src/generic/utils/currency.rs | 4 + .../src/generic/utils/xcm.rs | 10 ++- 5 files changed, 70 insertions(+), 61 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 20c8e0a5eb..6c84dadfe2 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -37,11 +37,7 @@ use pallet_liquidity_pools_gateway::{Call as LiquidityPoolsGatewayCall, GatewayO use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheType}; use parity_scale_codec::Encode; use polkadot_core_primitives::BlakeTwo256; -use polkadot_parachain_primitives::primitives::{Id, ValidationCode}; -use polkadot_runtime_parachains::{ - paras, - paras::{ParaGenesisArgs, ParaKind}, -}; +use polkadot_parachain_primitives::primitives::Id; use runtime_common::{ account_conversion::AccountConverter, foreign_investments::IdentityPoolCurrencyConverter, @@ -54,8 +50,7 @@ use sp_runtime::{ AccountIdConversion, BadOrigin, ConstU32, Convert as C1, Convert as C2, EnsureAdd, Hash, One, StaticLookup, Zero, }, - BoundedVec, BuildStorage, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, - WeakBoundedVec, + BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, WeakBoundedVec, }; use staging_xcm::{ prelude::XCM_VERSION, diff --git a/runtime/integration-tests/src/generic/cases/proxy.rs b/runtime/integration-tests/src/generic/cases/proxy.rs index 509288e2f2..1cd97a8eb2 100644 --- a/runtime/integration-tests/src/generic/cases/proxy.rs +++ b/runtime/integration-tests/src/generic/cases/proxy.rs @@ -1,13 +1,9 @@ use cfg_primitives::Balance; -use cfg_types::{tokens::CrossChainTransferability, xcm::XcmMetadata}; -use frame_support::{assert_err, assert_ok, traits::Get}; +use cfg_types::tokens::{AssetMetadata, CurrencyId}; +use frame_support::{assert_err, assert_ok}; use frame_system::RawOrigin; use sp_runtime::{traits::StaticLookup, DispatchResult}; -use staging_xcm::{ - prelude::Parachain, - v4::{Junction, Location, WeightLimit}, - VersionedLocation, -}; +use staging_xcm::v4::WeightLimit; use crate::{ generic::{ @@ -18,9 +14,9 @@ use crate::{ runtime_env::RuntimeEnv, }, utils::{ - self, - currency::{cfg, register_currency, usd6, CurrencyInfo, Usd6}, + currency::{cfg, usd6, CurrencyInfo, CustomCurrency, Usd6}, genesis::{self, Genesis}, + xcm::{account_location, enable_para_to_sibling_communication, transferable_metadata}, }, }, utils::accounts::Keyring, @@ -55,20 +51,28 @@ fn configure_proxy_and_transfer(proxy_type: T::ProxyType) -> Dispatc fn configure_proxy_and_x_transfer( proxy_type: T::ProxyType, ) -> DispatchResult { - let curr = CustomCurrency(Usd6.id(), transferable_metadata::(6)); + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 6, + ..transferable_metadata(Some(T::FudgeHandle::PARA_ID)) + }, + ); let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(FOR_FEES)) .add(genesis::tokens::(vec![(curr.id(), INITIAL)])) - .add(genesis::assets::(vec![(curr.id(), curr.metadata())])) + .add(genesis::assets::(vec![(curr.id(), &curr.metadata())])) .storage(), ); + enable_para_to_sibling_communication::(&mut env); + let call = pallet_restricted_xtokens::Call::transfer { - currency_id: Usd6.id(), + currency_id: curr.id(), amount: TRANSFER_AMOUNT, - dest: account_location(1, T::FudgeHandle::SIBLING_ID, TO.id()), + dest: account_location(1, Some(T::FudgeHandle::SIBLING_ID), TO.id()), dest_weight_limit: WeightLimit::Unlimited, } .into(); diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index 9e14b17a35..0cd5a73c7d 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -1,7 +1,7 @@ -use cfg_types::tokens::{AssetMetadata, CurrencyId}; +use cfg_types::tokens::{AssetMetadata, CurrencyId, CurrencyId::Native}; use frame_support::{assert_ok, dispatch::RawOrigin}; use orml_traits::MultiCurrency; -use staging_xcm::v4::{Junction::*, Junctions::Here, Location, WeightLimit}; +use staging_xcm::v4::{Junction::*, Junctions::Here, WeightLimit}; use crate::{ generic::{ @@ -27,9 +27,19 @@ const TRANSFER: u32 = 20; type Relay = FudgeRelayRuntime; +fn create_transfeable_currency(decimals: u32, para_id: Option) -> CustomCurrency { + CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals, + ..transferable_metadata(para_id) + }, + ) +} + #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_foreign_tokens() { - let curr = CustomCurrency(CurrencyId::ForeignAsset(1), transferable_metadata::(6)); + let curr = create_transfeable_currency(6, Some(T::FudgeHandle::PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -71,17 +81,16 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { #[test_runtimes(all)] fn para_to_sibling_with_native_to_foreign_tokens() { - let metadata = transferable_metadata::(18); - let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); + let curr = create_transfeable_currency(18, Some(T::FudgeHandle::PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), Genesis::default() .add(genesis::balances::(cfg(INITIAL))) - .add(genesis::assets::([(CurrencyId::Native, &metadata)])) + .add(genesis::assets::([(Native, &curr.metadata())])) .storage(), Genesis::default() - .add(genesis::assets::([(xnative.id(), &metadata)])) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) .storage(), ); @@ -90,7 +99,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Alice.id()).into(), - CurrencyId::Native, + Native, cfg(TRANSFER), account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, @@ -106,25 +115,24 @@ fn para_to_sibling_with_native_to_foreign_tokens() { env.sibling_state_mut(|| { assert_eq!( - orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Bob.id()), - xnative.val(TRANSFER) + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), + curr.val(TRANSFER) ); }); } #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_native_tokens() { - let metadata = transferable_metadata::(18); - let xnative = CustomCurrency(CurrencyId::ForeignAsset(1), metadata.clone()); + let curr = create_transfeable_currency(18, Some(T::FudgeHandle::PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), Genesis::default() - .add(genesis::tokens::([(xnative.id(), xnative.val(INITIAL))])) - .add(genesis::assets::([(xnative.id(), &metadata)])) + .add(genesis::tokens::([(curr.id(), curr.val(INITIAL))])) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) .storage(), Genesis::default() - .add(genesis::assets::([(CurrencyId::Native, &metadata)])) + .add(genesis::assets::([(Native, &curr.metadata())])) .storage(), ); @@ -133,15 +141,15 @@ fn para_to_sibling_with_foreign_to_native_tokens() { env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Alice.id()).into(), - xnative.id(), - xnative.val(TRANSFER), + curr.id(), + curr.val(TRANSFER), account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); assert_eq!( - orml_tokens::Pallet::::free_balance(xnative.id(), &Keyring::Alice.id()), - xnative.val(INITIAL) - xnative.val(TRANSFER) + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Alice.id()), + curr.val(INITIAL) - curr.val(TRANSFER) ); }); @@ -156,21 +164,15 @@ fn para_to_sibling_with_foreign_to_native_tokens() { } #[test_runtimes(all)] -fn from_to_relay_using_relay_native_tokens() { - let xrelay = CustomCurrency( - CurrencyId::ForeignAsset(1), - AssetMetadata { - location: Some(Location::parent().into()), - ..transferable_metadata::(10) - }, - ); +fn para_from_to_relay_using_relay_native_tokens() { + let curr = create_transfeable_currency(10, None); let mut env = FudgeEnv::::from_storage( Genesis::default() - .add(genesis::balances::>(xrelay.val(INITIAL))) + .add(genesis::balances::>(curr.val(INITIAL))) .storage(), Genesis::default() - .add(genesis::assets::([(xrelay.id(), &xrelay.metadata())])) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) .storage(), Default::default(), ); @@ -183,13 +185,13 @@ fn from_to_relay_using_relay_native_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), account_location(0, None, Keyring::Bob.id()), - Box::new((Here, xrelay.val(TRANSFER)).into()), + Box::new((Here, curr.val(TRANSFER)).into()), 0, )); assert_eq!( pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), - (xrelay.val(INITIAL) - xrelay.val(TRANSFER)).approx(0.01) + (curr.val(INITIAL) - curr.val(TRANSFER)).approx(0.01) ); }); @@ -197,8 +199,8 @@ fn from_to_relay_using_relay_native_tokens() { env.parachain_state_mut(|| { assert_eq!( - orml_tokens::Pallet::::free_balance(xrelay.id(), &Keyring::Bob.id()), - xrelay.val(TRANSFER) + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), + curr.val(TRANSFER) ); }); @@ -208,15 +210,15 @@ fn from_to_relay_using_relay_native_tokens() { env.parachain_state_mut(|| { assert_ok!(orml_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Bob.id()).into(), - xrelay.id(), - xrelay.val(TRANSFER / 2), + curr.id(), + curr.val(TRANSFER / 2), account_location(1, None, Keyring::Alice.id()), WeightLimit::Unlimited, )); assert_eq!( - orml_tokens::Pallet::::free_balance(xrelay.id(), &Keyring::Bob.id()), - (xrelay.val(TRANSFER) - xrelay.val(TRANSFER / 2)).approx(0.01) + orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), + (curr.val(TRANSFER) - curr.val(TRANSFER / 2)).approx(0.01) ); }); @@ -225,7 +227,7 @@ fn from_to_relay_using_relay_native_tokens() { env.relay_state_mut(|| { assert_eq!( pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), - (xrelay.val(INITIAL) - xrelay.val(TRANSFER) + xrelay.val(TRANSFER / 2)).approx(0.01) + (curr.val(INITIAL) - curr.val(TRANSFER) + curr.val(TRANSFER / 2)).approx(0.01) ); }); } diff --git a/runtime/integration-tests/src/generic/utils/currency.rs b/runtime/integration-tests/src/generic/utils/currency.rs index b53cb4815c..5234d8ff4b 100644 --- a/runtime/integration-tests/src/generic/utils/currency.rs +++ b/runtime/integration-tests/src/generic/utils/currency.rs @@ -176,6 +176,10 @@ impl CurrencyInfo for CustomCurrency { fn custom(&self) -> CustomMetadata { self.1.additional } + + fn metadata(&self) -> AssetMetadata { + self.1.clone() + } } impl CustomCurrency { diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index dbb82a13e6..8812861539 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -82,10 +82,14 @@ pub fn account_location( })) } -pub fn transferable_metadata(decimals: u32) -> AssetMetadata { +pub fn transferable_metadata(origin_para_id: Option) -> AssetMetadata { + let location = match origin_para_id { + Some(para_id) => Location::new(1, Parachain(para_id)), + None => Location::parent(), + }; + AssetMetadata { - decimals, - location: Some(Location::new(1, Parachain(T::FudgeHandle::PARA_ID)).into()), + location: Some(VersionedLocation::V4(location)), additional: CustomMetadata { transferability: CrossChainTransferability::xcm_with_fees(0), ..Default::default() From 8dd05e3340086978a4a75cb899cc8bfd8973e1a1 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 13 Jun 2024 13:15:27 +0200 Subject: [PATCH 07/21] assets tests --- .../src/generic/cases/assets.rs | 54 +++++ .../src/generic/cases/liquidity_pools.rs | 196 ------------------ runtime/integration-tests/src/generic/mod.rs | 1 + 3 files changed, 55 insertions(+), 196 deletions(-) create mode 100644 runtime/integration-tests/src/generic/cases/assets.rs diff --git a/runtime/integration-tests/src/generic/cases/assets.rs b/runtime/integration-tests/src/generic/cases/assets.rs new file mode 100644 index 0000000000..56cf7e24bd --- /dev/null +++ b/runtime/integration-tests/src/generic/cases/assets.rs @@ -0,0 +1,54 @@ +use cfg_types::tokens::CurrencyId; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin}; +use sp_runtime::{DispatchError, DispatchError::BadOrigin}; + +use crate::{ + generic::{ + config::Runtime, env::Env, envs::runtime_env::RuntimeEnv, utils::currency::default_metadata, + }, + utils::orml_asset_registry, +}; + +#[test_runtimes(all)] +fn authority_configured() { + let mut env = RuntimeEnv::::default(); + + env.parachain_state_mut(|| { + assert_ok!(orml_asset_registry::Pallet::::register_asset( + RawOrigin::Root.into(), + default_metadata(), + Some(CurrencyId::Native) + )); + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + RawOrigin::Root.into(), + default_metadata(), + Some(CurrencyId::ForeignAsset(42)) + )); + + assert_noop!( + orml_asset_registry::Pallet::::register_asset( + RawOrigin::Root.into(), + default_metadata(), + Some(CurrencyId::Tranche(42, [1; 16])) + ), + BadOrigin + ); + }); +} + +#[test_runtimes(all)] +fn processor_configured() { + let mut env = RuntimeEnv::::default(); + + env.parachain_state_mut(|| { + assert_noop!( + orml_asset_registry::Pallet::::register_asset( + RawOrigin::Root.into(), + default_metadata(), + None + ), + DispatchError::Other("asset-registry: AssetId is required") + ); + }); +} diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 2abe1e5295..34744a0f91 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -5061,104 +5061,6 @@ mod altair { use utils::*; - mod asset_registry { - use super::*; - - #[test_runtimes([altair])] - fn register_air_works() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 0, - 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) - )); - }); - } - - #[test_runtimes([altair])] - fn register_foreign_asset_works() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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 - #[test_runtimes([altair])] - fn register_tranche_asset_blocked() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [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 - ); - }); - } - } - mod currency_id_convert { use super::*; @@ -5587,104 +5489,6 @@ mod centrifuge { use utils::*; - mod asset_registry { - use super::*; - - #[test_runtimes([centrifuge])] - fn register_cfg_works() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 0, - 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) - )); - }); - } - - #[test_runtimes([centrifuge])] - fn register_foreign_asset_works() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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 - #[test_runtimes([centrifuge])] - fn register_tranche_asset_blocked() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - let meta: AssetMetadata = AssetMetadata { - decimals: 12, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [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 - ); - }); - } - } - mod currency_id_convert { use super::*; diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index 72671baec3..22de9a5a98 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -11,6 +11,7 @@ pub mod utils; // Test cases mod cases { mod account_derivation; + mod assets; mod block_rewards; mod ethereum_transaction; mod example; From bf338c84158c933080991529de18f5a4346cfa07 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 13 Jun 2024 16:19:10 +0200 Subject: [PATCH 08/21] currency conversion tests --- .../src/generic/cases/currency_conversions.rs | 100 +++++ .../src/generic/cases/liquidity_pools.rs | 391 +----------------- .../src/generic/cases/xtransfers.rs | 10 +- runtime/integration-tests/src/generic/mod.rs | 1 + .../src/generic/utils/genesis.rs | 7 + .../src/generic/utils/xcm.rs | 12 +- 6 files changed, 124 insertions(+), 397 deletions(-) create mode 100644 runtime/integration-tests/src/generic/cases/currency_conversions.rs diff --git a/runtime/integration-tests/src/generic/cases/currency_conversions.rs b/runtime/integration-tests/src/generic/cases/currency_conversions.rs new file mode 100644 index 0000000000..879c40fe00 --- /dev/null +++ b/runtime/integration-tests/src/generic/cases/currency_conversions.rs @@ -0,0 +1,100 @@ +use cfg_types::tokens::CurrencyId; +use orml_traits::asset_registry::AssetMetadata; +use runtime_common::xcm::CurrencyIdConvert; +use sp_runtime::traits::Convert; +use staging_xcm::{ + v4::{Junction::*, Junctions::Here, Location}, + VersionedLocation, +}; + +use crate::generic::{ + config::Runtime, + env::Env, + envs::runtime_env::RuntimeEnv, + utils::{ + currency::{default_metadata, CurrencyInfo, CustomCurrency}, + genesis::{self, Genesis}, + xcm::transferable_custom, + }, +}; + +const PARA_ID: u32 = 1000; + +#[test_runtimes(all)] +fn convert_transferable_asset() { + // The way the native currency is represented relative to its runtime + let location_inner = Location::new(0, Here); + + // The canonical way the native currency is represented out in the wild + let location_canonical = Location::new(1, Parachain(PARA_ID)); + + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 18, + location: Some(VersionedLocation::V4(location_canonical.clone())), + additional: transferable_custom(), + ..default_metadata() + }, + ); + + let env = RuntimeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::parachain_id::(PARA_ID)) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .storage(), + ); + + env.parachain_state(|| { + assert_eq!( + CurrencyIdConvert::::convert(location_inner), + Some(curr.id()), + ); + + assert_eq!( + CurrencyIdConvert::::convert(curr.id()), + Some(location_canonical) + ) + }); +} + +#[test_runtimes(all)] +fn cannot_convert_nontransferable_asset() { + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 18, + location: Some(VersionedLocation::V4(Location::new(1, Parachain(PARA_ID)))), + additional: Default::default(), // <- Not configured for transfers + ..default_metadata() + }, + ); + + let env = RuntimeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::parachain_id::(PARA_ID)) + .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .storage(), + ); + + env.parachain_state(|| { + assert_eq!( + CurrencyIdConvert::::convert(Location::new(0, Here)), + Some(curr.id()), + ); + + assert_eq!(CurrencyIdConvert::::convert(curr.id()), None); + }); +} + +#[test_runtimes(all)] +fn convert_unknown_location() { + let env = RuntimeEnv::::default(); + + env.parachain_state(|| { + assert_eq!( + CurrencyIdConvert::::convert(Location::new(0, Here)), + None, + ); + }); +} diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 34744a0f91..cc6b7f483d 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -17,7 +17,6 @@ use cfg_types::{ tokens::{AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata}, xcm::XcmMetadata, }; -use cfg_utils::vec_to_fixed_array; use frame_support::{ assert_noop, assert_ok, dispatch::RawOrigin, @@ -35,20 +34,16 @@ use pallet_investments::CollectOutcome; use pallet_liquidity_pools::Message; use pallet_liquidity_pools_gateway::{Call as LiquidityPoolsGatewayCall, GatewayOrigin}; use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheType}; -use parity_scale_codec::Encode; use polkadot_core_primitives::BlakeTwo256; use polkadot_parachain_primitives::primitives::Id; use runtime_common::{ - account_conversion::AccountConverter, - foreign_investments::IdentityPoolCurrencyConverter, - xcm::general_key, - xcm_fees::{default_per_second, ksm_per_second}, + account_conversion::AccountConverter, foreign_investments::IdentityPoolCurrencyConverter, + xcm::general_key, xcm_fees::default_per_second, }; use sp_core::{Get, H160, U256}; use sp_runtime::{ traits::{ - AccountIdConversion, BadOrigin, ConstU32, Convert as C1, Convert as C2, EnsureAdd, Hash, - One, StaticLookup, Zero, + AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, Hash, One, StaticLookup, Zero, }, BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, WeakBoundedVec, }; @@ -4981,242 +4976,7 @@ mod development { } } -mod altair { - use altair_runtime::{xcm::CurrencyIdConvert, PoolPalletIndex}; - - pub const KSM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1000); - - use super::*; - - mod utils { - use super::*; - - pub fn register_air() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - 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: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000, - location: Some(VersionedLocation::V4(Location::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 * decimals(currency_decimals::NATIVE) - } - - pub fn ksm(amount: Balance) -> Balance { - amount * decimals(currency_decimals::KSM) - } - - pub fn foreign(amount: Balance, num_decimals: u32) -> Balance { - amount * decimals(num_decimals) - } - - pub fn air_fee() -> Balance { - fee(currency_decimals::NATIVE) - } - - // The fee associated with transferring KSM tokens - pub fn ksm_fee() -> Balance { - calc_fee(ksm_per_second()) - } - } - - use utils::*; - - mod currency_id_convert { - use super::*; - - #[test_runtimes([altair])] - fn convert_air() { - let mut env = FudgeEnv::::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: Location = - Location::new(0, general_key(parachains::kusama::altair::AIR_KEY)); - - // register air - register_air::(); - - assert_eq!( - >::convert(air_location_inner), - Some(CurrencyId::Native), - ); - - // The canonical way AIR is represented out in the wild - let air_location_canonical: Location = Location::new( - 1, - [ - 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. - #[test_runtimes([altair])] - fn convert_tranche() { - let mut env = FudgeEnv::::default(); - - let tranche_currency = CurrencyId::Tranche(401, [0; 16]); - let tranche_id = - WeakBoundedVec::>::force_from(tranche_currency.encode(), None); - let tranche_multilocation = Location::new( - 1, - [ - Parachain(T::FudgeHandle::PARA_ID), - PalletInstance(PoolPalletIndex::get()), - GeneralKey { - length: tranche_id.len() as u8, - data: vec_to_fixed_array(tranche_id), - }, - ], - ); - - env.parachain_state_mut(|| { - assert_eq!( - >::convert(tranche_multilocation), - None, - ); - }); - - env.parachain_state_mut(|| { - assert_eq!( - >::convert(tranche_currency), - None - ) - }); - } - - #[test_runtimes([altair])] - fn convert_ausd() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - assert_eq!(parachains::kusama::karura::AUSD_KEY, &[0, 129]); - - let ausd_location: Location = Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - general_key(parachains::kusama::karura::AUSD_KEY), - ], - ); - - register_ausd::(); - - assert_eq!( - >::convert(ausd_location.clone()), - Some(AUSD_CURRENCY_ID), - ); - - assert_eq!( - >::convert(AUSD_CURRENCY_ID), - Some(ausd_location) - ) - }); - } - - #[test_runtimes([altair])] - fn convert_ksm() { - let mut env = FudgeEnv::::default(); - - let ksm_location: Location = Location::parent().into(); - - env.parachain_state_mut(|| { - register_ksm::(); - - assert_eq!( - >::convert(ksm_location.clone()), - Some(KSM_ASSET_ID), - ); - - assert_eq!( - >::convert(KSM_ASSET_ID), - Some(ksm_location) - ) - }); - } - - #[test_runtimes([altair])] - fn convert_unkown_multilocation() { - let mut env = FudgeEnv::::default(); - - let unknown_location: Location = - Location::new(1, [Parachain(T::FudgeHandle::PARA_ID), general_key(&[42])]); - - env.parachain_state_mut(|| { - assert!(>::convert(unknown_location).is_none()); - }); - } - - #[test_runtimes([altair])] - fn convert_unsupported_currency() { - let mut env = FudgeEnv::::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 - ) - }); - } - } -} - mod centrifuge { - use centrifuge_runtime::xcm::CurrencyIdConvert; - use super::*; mod utils { @@ -5489,151 +5249,6 @@ mod centrifuge { use utils::*; - mod currency_id_convert { - use super::*; - - #[test_runtimes([centrifuge])] - fn convert_cfg() { - let mut env = FudgeEnv::::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: Location = - Location::new(0, general_key(parachains::polkadot::centrifuge::CFG_KEY)); - - register_cfg::(T::FudgeHandle::PARA_ID); - - assert_eq!( - >::convert(cfg_location_inner), - Some(CurrencyId::Native), - ); - - // The canonical way CFG is represented out in the wild - let cfg_location_canonical: Location = Location::new( - 1, - [ - 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 Location, that `CurrencyIdConvert` can look it up given an - /// identical location in XCM v3. - #[test_runtimes([centrifuge])] - fn convert_cfg_xcm_v2() { - let mut env = FudgeEnv::::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: Location = - Location::new(0, general_key(parachains::polkadot::centrifuge::CFG_KEY)); - - assert_eq!( - >::convert(cfg_location_inner), - Some(CurrencyId::Native), - ); - - // The canonical way CFG is represented out in the wild - let cfg_location_canonical: Location = Location::new( - 1, - [ - 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_runtimes([centrifuge])] - fn convert_no_xcm_token() { - let mut env = FudgeEnv::::default(); - - env.parachain_state_mut(|| { - register_no_xcm_token::(); - - assert_eq!( - >::convert(NO_XCM_ASSET_ID), - None - ) - }); - } - - #[test_runtimes([centrifuge])] - fn convert_dot() { - let mut env = FudgeEnv::::default(); - - let dot_location: Location = Location::parent(); - - env.parachain_state_mut(|| { - register_dot::(); - - assert_eq!( - >::convert(dot_location.clone()), - Some(DOT_ASSET_ID), - ); - - assert_eq!( - >::convert(DOT_ASSET_ID), - Some(dot_location) - ) - }); - } - - #[test_runtimes([centrifuge])] - fn convert_unknown_multilocation() { - let mut env = FudgeEnv::::default(); - - let unknown_location: Location = Location::new( - 1, - [ - Parachain(T::FudgeHandle::PARA_ID), - general_key([42].as_ref()), - ], - ); - - env.parachain_state_mut(|| { - assert!(>::convert(unknown_location).is_none()); - }); - } - - #[test_runtimes([centrifuge])] - fn convert_unsupported_currency() { - let mut env = FudgeEnv::::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 - ) - }); - } - } - mod restricted_transfers { use cfg_types::tokens::{CurrencyId::Native, FilterCurrency}; diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index 0cd5a73c7d..1eeb7c84ef 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -71,7 +71,7 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { env.pass(Blocks::ByNumber(2)); - env.sibling_state_mut(|| { + env.sibling_state(|| { assert_eq!( orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), curr.val(TRANSFER) @@ -113,7 +113,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { env.pass(Blocks::ByNumber(2)); - env.sibling_state_mut(|| { + env.sibling_state(|| { assert_eq!( orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), curr.val(TRANSFER) @@ -155,7 +155,7 @@ fn para_to_sibling_with_foreign_to_native_tokens() { env.pass(Blocks::ByNumber(2)); - env.sibling_state_mut(|| { + env.sibling_state(|| { assert_eq!( pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), cfg(TRANSFER) @@ -197,7 +197,7 @@ fn para_from_to_relay_using_relay_native_tokens() { env.pass(Blocks::ByNumber(2)); - env.parachain_state_mut(|| { + env.parachain_state(|| { assert_eq!( orml_tokens::Pallet::::free_balance(curr.id(), &Keyring::Bob.id()), curr.val(TRANSFER) @@ -224,7 +224,7 @@ fn para_from_to_relay_using_relay_native_tokens() { env.pass(Blocks::ByNumber(2)); - env.relay_state_mut(|| { + env.relay_state(|| { assert_eq!( pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), (curr.val(INITIAL) - curr.val(TRANSFER) + curr.val(TRANSFER / 2)).approx(0.01) diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index 22de9a5a98..13b54573cb 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -13,6 +13,7 @@ mod cases { mod account_derivation; mod assets; mod block_rewards; + mod currency_conversions; mod ethereum_transaction; mod example; mod investments; diff --git a/runtime/integration-tests/src/generic/utils/genesis.rs b/runtime/integration-tests/src/generic/utils/genesis.rs index 65a52e786b..1648a95ba7 100644 --- a/runtime/integration-tests/src/generic/utils/genesis.rs +++ b/runtime/integration-tests/src/generic/utils/genesis.rs @@ -113,3 +113,10 @@ pub fn block_rewards( last_update: Default::default(), } } + +pub fn parachain_id(para_id: u32) -> impl BuildStorage { + staging_parachain_info::GenesisConfig:: { + _config: Default::default(), + parachain_id: para_id.into(), + } +} diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index 8812861539..5d20f93a47 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -82,6 +82,13 @@ pub fn account_location( })) } +pub fn transferable_custom() -> CustomMetadata { + CustomMetadata { + transferability: CrossChainTransferability::xcm_with_fees(0), + ..Default::default() + } +} + pub fn transferable_metadata(origin_para_id: Option) -> AssetMetadata { let location = match origin_para_id { Some(para_id) => Location::new(1, Parachain(para_id)), @@ -90,10 +97,7 @@ pub fn transferable_metadata(origin_para_id: Option) -> AssetMetadata { AssetMetadata { location: Some(VersionedLocation::V4(location)), - additional: CustomMetadata { - transferability: CrossChainTransferability::xcm_with_fees(0), - ..Default::default() - }, + additional: transferable_custom(), ..default_metadata() } } From 126eeb586c27ba4c84866270ff70466e89ca0ee1 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 13 Jun 2024 16:31:04 +0200 Subject: [PATCH 09/21] fix cargo fmt --- .../src/generic/cases/liquidity_pools.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index cc6b7f483d..f49e84e3d0 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -256,7 +256,9 @@ mod development { token_name: BoundedVec::< u8, ::StringLimit, - >::try_from("A highly advanced tranche".as_bytes().to_vec()) + >::try_from( + "A highly advanced tranche".as_bytes().to_vec() + ) .expect("Can create BoundedVec for token name"), token_symbol: BoundedVec::< u8, @@ -4730,7 +4732,9 @@ mod development { axelar_target_chain: BoundedVec::< u8, ConstU32, - >::try_from("ethereum".as_bytes().to_vec()) + >::try_from( + "ethereum".as_bytes().to_vec() + ) .unwrap(), axelar_target_contract: H160::from_low_u64_be(111), _marker: Default::default(), From 891bfe779f10c76a5d90fe562d1d6ca4df53cb17 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Fri, 14 Jun 2024 10:20:56 +0200 Subject: [PATCH 10/21] fix tests --- .../src/generic/cases/liquidity_pools.rs | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index f49e84e3d0..560eedf5c5 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -1083,22 +1083,6 @@ mod development { outbound_message }); - - let expected_event = - pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { - sender, - domain, - message, - nonce: T::OutboundMessageNonce::one(), - }; - - env.pass(Blocks::UntilEvent { - event: expected_event.clone().into(), - limit: 3, - }); - - env.check_event(expected_event) - .expect("expected RouterExecutionSuccess event"); } #[test_runtimes([development])] @@ -4618,7 +4602,7 @@ mod development { }); env.check_event(expected_event) - .expect("expected RouterExecutionSuccess event"); + .expect("expected OutboundMessageExecutionSuccess event"); // Router not found let unused_domain = Domain::EVM(1234); @@ -4653,6 +4637,8 @@ mod development { setup_test(&mut env); + enable_para_to_sibling_communication::(&mut env); + let msg = Message::::Transfer { currency: 0, sender: Keyring::Alice.into(), @@ -4701,7 +4687,7 @@ mod development { }); env.check_event(expected_event) - .expect("expected RouterExecutionSuccess event"); + .expect("expected OutboundMessageExecutionSuccess event"); } type RouterCreationFn = From d781110a26e5c3f77f1f4d46806d3bd8c3e746d7 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Fri, 14 Jun 2024 12:50:43 +0200 Subject: [PATCH 11/21] reduce xcm restricted_transfer tests --- .../src/generic/cases/currency_conversions.rs | 4 +- .../src/generic/cases/liquidity_pools.rs | 623 +----------------- .../src/generic/cases/proxy.rs | 2 +- .../src/generic/cases/restricted_transfers.rs | 376 +++++------ .../src/generic/cases/xtransfers.rs | 14 +- .../src/generic/utils/currency.rs | 4 + 6 files changed, 193 insertions(+), 830 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/currency_conversions.rs b/runtime/integration-tests/src/generic/cases/currency_conversions.rs index 879c40fe00..a690165203 100644 --- a/runtime/integration-tests/src/generic/cases/currency_conversions.rs +++ b/runtime/integration-tests/src/generic/cases/currency_conversions.rs @@ -41,7 +41,7 @@ fn convert_transferable_asset() { let env = RuntimeEnv::::from_parachain_storage( Genesis::default() .add(genesis::parachain_id::(PARA_ID)) - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); @@ -73,7 +73,7 @@ fn cannot_convert_nontransferable_asset() { let env = RuntimeEnv::::from_parachain_storage( Genesis::default() .add(genesis::parachain_id::(PARA_ID)) - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 560eedf5c5..17d1497a7b 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -74,7 +74,7 @@ pub const USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); pub const AUSD_ED: Balance = 1_000_000_000; pub const USDT_ED: Balance = 10_000; -pub mod utils { +mod utils { use super::*; pub fn parachain_account(id: u32) -> AccountId { @@ -1040,7 +1040,7 @@ mod development { setup_test(&mut env); - let (domain, sender, message) = env.parachain_state_mut(|| { + env.parachain_state_mut(|| { let gateway_sender = ::Sender::get(); let currency_id = AUSD_CURRENCY_ID; @@ -1080,8 +1080,6 @@ mod development { evm_address, }, ); - - outbound_message }); } @@ -5240,314 +5238,16 @@ mod centrifuge { use utils::*; mod restricted_transfers { - use cfg_types::tokens::{CurrencyId::Native, FilterCurrency}; + use cfg_types::tokens::FilterCurrency; use super::*; use crate::generic::envs::runtime_env::RuntimeEnv; const TRANSFER_AMOUNT: u128 = 10; - fn xcm_location() -> VersionedLocation { - VersionedLocation::V4(Location::new( - 1, - AccountId32 { - id: Keyring::Alice.into(), - network: None, - }, - )) - } - - fn allowed_xcm_location() -> RestrictedTransferLocation { - RestrictedTransferLocation::Xcm(Box::new(xcm_location())) - } - - fn add_allowance( - account: Keyring, - asset: CurrencyId, - location: RestrictedTransferLocation, - ) { - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(account.into()).into(), - FilterCurrency::Specific(asset), - location - ) - ); - } - - #[test_runtimes([centrifuge])] - fn restrict_cfg_extrinsic() { - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(TRANSFER_AMOUNT + 10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - USDC, - T::ExistentialDeposit::get() + usdc(TRANSFER_AMOUNT), - )], - }) - .storage(), - ); - - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = env - .parachain_state_mut(|| { - // NOTE: The para-id is not relevant here - register_cfg::(2031); - - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::All, - RestrictedTransferLocation::Local(Keyring::Bob.id()) - ) - ); - - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let call = pallet_balances::Call::::transfer_allow_death { - dest: Keyring::Charlie.into(), - value: cfg(TRANSFER_AMOUNT), - }; - env.submit_now(Keyring::Alice, call).unwrap(); - - let call = pallet_balances::Call::::transfer_allow_death { - dest: Keyring::Bob.into(), - value: cfg(TRANSFER_AMOUNT), - }; - let fee = env.submit_now(Keyring::Alice, call).unwrap(); - - // Restrict also CFG local - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - cfg(TRANSFER_AMOUNT) - 2 * fee - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } - - #[test_runtimes([centrifuge])] - fn restrict_all() { - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(TRANSFER_AMOUNT + 10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - USDC, - T::ExistentialDeposit::get() + usdc(TRANSFER_AMOUNT), - )], - }) - .storage(), - ); - - // Set allowance - env.parachain_state_mut(|| { - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::All, - RestrictedTransferLocation::Local(Keyring::Bob.id()) - ) - ); - }); - - // Restrict USDC local - env.parachain_state_mut(|| { - register_usdc::(1000); - - let pre_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let pre_transfer_bob = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Bob.id()); - let pre_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - assert_noop!( - pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Charlie.into(), - USDC, - lp_eth_usdc(TRANSFER_AMOUNT) - ), - pallet_restricted_tokens::Error::::PreConditionsNotMet - ); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - - assert_ok!(pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Bob.into(), - USDC, - usdc(TRANSFER_AMOUNT) - ),); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let after_transfer_bob = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Bob.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - usdc(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + usdc(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - - // Restrict also CFG local - env.parachain_state_mut(|| { - // NOTE: The para-id is not relevant here - register_cfg::(2031); - - let pre_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let pre_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let pre_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_noop!( - pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Charlie.into(), - Native, - cfg(TRANSFER_AMOUNT) - ), - pallet_restricted_tokens::Error::::PreConditionsNotMet - ); - - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - - assert_ok!(pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Bob.into(), - Native, - cfg(TRANSFER_AMOUNT) - ),); - - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - cfg(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } - - #[test_runtimes([centrifuge])] - fn restrict_lp_eth_usdc_transfer() { - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - LP_ETH_USDC, - T::ExistentialDeposit::get() + lp_eth_usdc(TRANSFER_AMOUNT), - )], - }) - .storage(), - ); - - env.parachain_state_mut(|| { - register_lp_eth_usdc::(); - - let pre_transfer_alice = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Alice.id()); - let pre_transfer_bob = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Bob.id()); - let pre_transfer_charlie = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Charlie.id()); - - add_allowance::( - Keyring::Alice, - LP_ETH_USDC, - RestrictedTransferLocation::Local(Keyring::Bob.id()), - ); - - assert_noop!( - pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Charlie.into(), - LP_ETH_USDC, - lp_eth_usdc(TRANSFER_AMOUNT) - ), - pallet_restricted_tokens::Error::::PreConditionsNotMet - ); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Alice.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - - assert_ok!(pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Bob.into(), - LP_ETH_USDC, - lp_eth_usdc(TRANSFER_AMOUNT) - ),); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Alice.id()); - let after_transfer_bob = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Bob.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(LP_ETH_USDC, &Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - lp_eth_usdc(TRANSFER_AMOUNT) - ); - assert_eq!( - after_transfer_bob, - pre_transfer_bob + lp_eth_usdc(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } - #[test_runtimes([centrifuge])] fn restrict_lp_eth_usdc_lp_transfer() { - let mut env = FudgeEnv::::from_parachain_storage( + let mut env = RuntimeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(10))) .add(orml_tokens::GenesisConfig:: { @@ -5608,10 +5308,12 @@ mod centrifuge { let domain_address = DomainAddress::EVM(1, receiver.into()); - add_allowance::( - Keyring::Alice, - LP_ETH_USDC, - RestrictedTransferLocation::Address(domain_address.clone()), + assert_ok!( + pallet_transfer_allowlist::Pallet::::add_transfer_allowance( + RawOrigin::Signed(Keyring::Alice.into()).into(), + FilterCurrency::Specific(LP_ETH_USDC), + RestrictedTransferLocation::Address(domain_address.clone()), + ) ); assert_noop!( @@ -5639,310 +5341,5 @@ mod centrifuge { ); }); } - - #[test_runtimes([centrifuge])] - fn restrict_usdc_transfer() { - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - USDC, - T::ExistentialDeposit::get() + usdc(TRANSFER_AMOUNT), - )], - }) - .storage(), - ); - - env.parachain_state_mut(|| { - register_usdc::(1000); - - let pre_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let pre_transfer_bob = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Bob.id()); - let pre_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - add_allowance::( - Keyring::Alice, - USDC, - RestrictedTransferLocation::Local(Keyring::Bob.id()), - ); - - assert_noop!( - pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Charlie.into(), - USDC, - lp_eth_usdc(TRANSFER_AMOUNT) - ), - pallet_restricted_tokens::Error::::PreConditionsNotMet - ); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - - assert_ok!(pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Bob.into(), - USDC, - usdc(TRANSFER_AMOUNT) - ),); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Alice.id()); - let after_transfer_bob = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Bob.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(USDC, &Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - usdc(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + usdc(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } - - #[test_runtimes([centrifuge])] - fn restrict_usdc_xcm_transfer() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .add(genesis::tokens::([(USDC, usdc(3_000))])) - .storage(), - ); - - enable_para_to_sibling_communication::(&mut env); - - env.parachain_state_mut(|| { - register_usdc::(T::FudgeHandle::SIBLING_ID); - - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::Specific(USDC), - RestrictedTransferLocation::Xcm(Box::new(VersionedLocation::V4( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - id: Keyring::Alice.into(), - network: None, - } - ] - ) - ))) - ) - ); - - assert_noop!( - pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - USDC, - usdc(1_000), - Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - id: Keyring::Bob.into(), - network: None, - } - ] - ) - .into() - ), - WeightLimit::Unlimited, - ), - pallet_transfer_allowlist::Error::::NoAllowanceForDestination - ); - - assert_ok!(pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - USDC, - usdc(1_000), - Box::new( - Location::new( - 1, - [ - Parachain(T::FudgeHandle::SIBLING_ID), - Junction::AccountId32 { - id: Keyring::Alice.into(), - network: None, - } - ] - ) - .into() - ), - WeightLimit::Unlimited, - )); - }); - } - - #[test_runtimes([centrifuge])] - fn restrict_dot_transfer() { - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - DOT_ASSET_ID, - T::ExistentialDeposit::get() + dot(TRANSFER_AMOUNT), - )], - }) - .storage(), - ); - - env.parachain_state_mut(|| { - register_dot::(); - - let pre_transfer_alice = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.id()); - let pre_transfer_bob = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Bob.id()); - let pre_transfer_charlie = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Charlie.id()); - - add_allowance::( - Keyring::Alice, - DOT_ASSET_ID, - RestrictedTransferLocation::Local(Keyring::Bob.id()), - ); - - assert_noop!( - pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Charlie.into(), - DOT_ASSET_ID, - dot(TRANSFER_AMOUNT) - ), - pallet_restricted_tokens::Error::::PreConditionsNotMet - ); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - - assert_ok!(pallet_restricted_tokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - Keyring::Bob.into(), - DOT_ASSET_ID, - dot(TRANSFER_AMOUNT) - ),); - - let after_transfer_alice = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.id()); - let after_transfer_bob = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Bob.id()); - let after_transfer_charlie = - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - dot(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + dot(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } - - #[test_runtimes([centrifuge])] - fn restrict_dot_xcm_transfer() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .storage(), - ); - - 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_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::new(1, Junctions::Here)), - XCM_VERSION, - )); - - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::Specific(DOT_ASSET_ID), - allowed_xcm_location() - ) - ); - - assert_noop!( - pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - DOT_ASSET_ID, - dot(1), - Box::new( - Location::new( - 1, - Junction::AccountId32 { - id: Keyring::Bob.into(), - network: None, - } - ) - .into() - ), - WeightLimit::Unlimited, - ), - pallet_transfer_allowlist::Error::::NoAllowanceForDestination - ); - - assert_ok!(pallet_restricted_xtokens::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - DOT_ASSET_ID, - dot(1), - Box::new( - Location::new( - 1, - 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(2)); - - env.relay_state_mut(|| { - assert_eq!( - pallet_balances::Pallet::>::free_balance( - &Keyring::Alice.into() - ), - 79857365914 - ); - }); - } } } diff --git a/runtime/integration-tests/src/generic/cases/proxy.rs b/runtime/integration-tests/src/generic/cases/proxy.rs index 1cd97a8eb2..8fa276a305 100644 --- a/runtime/integration-tests/src/generic/cases/proxy.rs +++ b/runtime/integration-tests/src/generic/cases/proxy.rs @@ -63,7 +63,7 @@ fn configure_proxy_and_x_transfer( Genesis::default() .add(genesis::balances::(FOR_FEES)) .add(genesis::tokens::(vec![(curr.id(), INITIAL)])) - .add(genesis::assets::(vec![(curr.id(), &curr.metadata())])) + .add(genesis::assets::(vec![(curr.id(), curr.metadata())])) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs index ab1af8deb7..cb6f31aa81 100644 --- a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs @@ -10,34 +10,35 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -mod cfg { - use cfg_primitives::{currency_decimals, Balance}; - use cfg_types::{ - locations::RestrictedTransferLocation, - tokens::{CurrencyId, FilterCurrency}, - }; - use frame_support::{assert_ok, dispatch::RawOrigin}; - use runtime_common::remarks::Remark; - use sp_runtime::traits::Zero; - - use crate::{ - generic::{ - config::Runtime, - env::Env, - envs::runtime_env::RuntimeEnv, - utils::{genesis, genesis::Genesis}, +use cfg_primitives::{currency_decimals, AccountId, Balance}; +use cfg_types::{ + locations::RestrictedTransferLocation, + tokens::{AssetMetadata, CurrencyId, FilterCurrency}, +}; +use cumulus_primitives_core::WeightLimit; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin}; +use runtime_common::remarks::Remark; +use sp_runtime::traits::Zero; + +use crate::{ + generic::{ + config::Runtime, + env::Env, + envs::runtime_env::RuntimeEnv, + utils::{ + currency::{cfg, CurrencyInfo, CustomCurrency}, + genesis, + genesis::Genesis, + xcm::{account_location, transferable_metadata}, }, - utils::accounts::Keyring, - }; + }, + utils::accounts::Keyring, +}; - const TRANSFER_AMOUNT: Balance = 100; +const TRANSFER_AMOUNT: u32 = 100; - pub fn decimals(decimals: u32) -> Balance { - 10u128.saturating_pow(decimals) - } - pub fn cfg(amount: Balance) -> Balance { - amount * decimals(currency_decimals::NATIVE) - } +mod local { + use super::*; fn setup(filter: FilterCurrency) -> RuntimeEnv { let mut env = RuntimeEnv::::from_parachain_storage( @@ -66,155 +67,76 @@ mod cfg { env } - fn validate_fail(who: Keyring, call: impl Into + Clone) { - // With FilterCurrencyAll - { - let mut env = setup::(FilterCurrency::All); - - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = - env.parachain_state(|| { - // NOTE: The para-id is not relevant here - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let fee = env.submit_now(who, call.clone()).unwrap(); - // NOTE: Only use fee, if submitter is Alice - let fee = if who != Keyring::Alice { 0 } else { fee }; - - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice - fee); - assert_eq!(after_transfer_bob, pre_transfer_bob); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } + fn people_balances() -> (Balance, Balance, Balance) { + ( + pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), + pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), + pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), + ) + } - // With FilterCurrency::Specific(CurrencyId::Native) - { - let mut env = setup::(FilterCurrency::Specific(CurrencyId::Native)); - - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = - env.parachain_state(|| { - // NOTE: The para-id is not relevant here - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let fee = env.submit_now(who, call).unwrap(); - // NOTE: Only use fee, if submitter is Alice - let fee = if who != Keyring::Alice { 0 } else { fee }; - - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!(after_transfer_alice, pre_transfer_alice - fee); - assert_eq!(after_transfer_bob, pre_transfer_bob); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } + fn process_ok( + env: &mut RuntimeEnv, + who: Keyring, + call: impl Into, + ) { + let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = + env.parachain_state(|| people_balances::()); + + let fee = env.submit_now(who, call).unwrap(); + // NOTE: Only use fee, if submitter is Alice + let fee = if who != Keyring::Alice { 0 } else { fee }; + + let (after_transfer_alice, after_transfer_bob, after_transfer_charlie) = + env.parachain_state(|| people_balances::()); + + assert_eq!( + after_transfer_alice, + pre_transfer_alice - fee - cfg(TRANSFER_AMOUNT) + ); + assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); + assert_eq!(after_transfer_charlie, pre_transfer_charlie); + } + + fn process_fail( + env: &mut RuntimeEnv, + who: Keyring, + call: impl Into, + ) { + let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = + env.parachain_state(|| people_balances::()); + + let fee = env.submit_now(who, call).unwrap(); + // NOTE: Only use fee, if submitter is Alice + let fee = if who != Keyring::Alice { 0 } else { fee }; + + let (after_transfer_alice, after_transfer_bob, after_transfer_charlie) = + env.parachain_state(|| people_balances::()); + + assert_eq!(after_transfer_alice, pre_transfer_alice - fee); + assert_eq!(after_transfer_bob, pre_transfer_bob); + assert_eq!(after_transfer_charlie, pre_transfer_charlie); } fn validate_ok(who: Keyring, call: impl Into + Clone) { - // With FilterCurrencyAll - { - let mut env = setup::(FilterCurrency::All); - - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = - env.parachain_state(|| { - // NOTE: The para-id is not relevant here - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let fee = env.submit_now(who, call.clone()).unwrap(); - - // NOTE: Only use fee, if submitter is Alice - let fee = if who != Keyring::Alice { 0 } else { fee }; - - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - fee - cfg(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } + let mut env = setup::(FilterCurrency::All); + process_ok(&mut env, who, call.clone()); - // With FilterCurrency::Specific(CurrencyId::Native) - { - let mut env = setup::(FilterCurrency::Specific(CurrencyId::Native)); - - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = - env.parachain_state(|| { - // NOTE: The para-id is not relevant here - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let fee = env.submit_now(who, call).unwrap(); - // NOTE: Only use fee, if submitter is Alice - let fee = if who != Keyring::Alice { 0 } else { fee }; - - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - fee - cfg(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); - } + let mut env = setup::(FilterCurrency::Specific(CurrencyId::Native)); + process_ok(&mut env, who, call.clone()); } - fn transfer_ok() -> pallet_balances::Call { - pallet_balances::Call::::transfer_allow_death { - dest: Keyring::Bob.into(), - value: cfg(TRANSFER_AMOUNT), - } + fn validate_fail(who: Keyring, call: impl Into + Clone) { + let mut env = setup::(FilterCurrency::All); + process_fail(&mut env, who, call.clone()); + + let mut env = setup::(FilterCurrency::Specific(CurrencyId::Native)); + process_fail(&mut env, who, call.clone()); } - fn transfer_fail() -> pallet_balances::Call { - pallet_balances::Call::::transfer_allow_death { - dest: Keyring::Charlie.into(), + fn transfer_to(dest: Keyring) -> pallet_balances::Call { + pallet_balances::Call::transfer_allow_death { + dest: dest.into(), value: cfg(TRANSFER_AMOUNT), } } @@ -227,38 +149,13 @@ mod cfg { .storage(), ); - let (pre_transfer_alice, pre_transfer_bob, pre_transfer_charlie) = - env.parachain_state(|| { - // NOTE: The para-id is not relevant here - ( - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()), - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()), - ) - }); - - let fee = env.submit_now(Keyring::Alice, transfer_ok::()).unwrap(); - - env.parachain_state(|| { - let after_transfer_alice = - pallet_balances::Pallet::::free_balance(&Keyring::Alice.id()); - let after_transfer_bob = pallet_balances::Pallet::::free_balance(&Keyring::Bob.id()); - let after_transfer_charlie = - pallet_balances::Pallet::::free_balance(&Keyring::Charlie.id()); - - assert_eq!( - after_transfer_alice, - pre_transfer_alice - fee - cfg(TRANSFER_AMOUNT) - ); - assert_eq!(after_transfer_bob, pre_transfer_bob + cfg(TRANSFER_AMOUNT)); - assert_eq!(after_transfer_charlie, pre_transfer_charlie); - }); + process_ok(&mut env, Keyring::Alice, transfer_to(Keyring::Bob)); } #[test_runtimes(all)] fn basic_transfer() { - validate_ok::(Keyring::Alice, transfer_ok::()); - validate_fail::(Keyring::Alice, transfer_fail::()); + validate_ok::(Keyring::Alice, transfer_to(Keyring::Bob)); + validate_fail::(Keyring::Alice, transfer_to(Keyring::Charlie)); } #[test_runtimes(all)] @@ -268,7 +165,7 @@ mod cfg { pallet_proxy::Call::::proxy { real: Keyring::Alice.into(), force_proxy_type: None, - call: Box::new(transfer_ok::().into()), + call: Box::new(transfer_to(Keyring::Bob).into()), }, ); validate_fail::( @@ -276,7 +173,7 @@ mod cfg { pallet_proxy::Call::::proxy { real: Keyring::Alice.into(), force_proxy_type: None, - call: Box::new(transfer_fail::().into()), + call: Box::new(transfer_to(Keyring::Charlie).into()), }, ); } @@ -290,7 +187,7 @@ mod cfg { force_proxy_type: None, call: Box::new( pallet_utility::Call::::batch { - calls: vec![transfer_ok::().into()], + calls: vec![transfer_to(Keyring::Bob).into()], } .into(), ), @@ -303,7 +200,7 @@ mod cfg { force_proxy_type: None, call: Box::new( pallet_utility::Call::::batch { - calls: vec![transfer_fail::().into()], + calls: vec![transfer_to(Keyring::Charlie).into()], } .into(), ), @@ -316,16 +213,16 @@ mod cfg { validate_ok::( Keyring::Alice, pallet_utility::Call::::batch { - calls: vec![transfer_ok::().into()], + calls: vec![transfer_to(Keyring::Bob).into()], }, ); validate_fail::( Keyring::Alice, pallet_utility::Call::::batch { calls: vec![ - transfer_fail::().into(), - transfer_fail::().into(), - transfer_fail::().into(), + transfer_to(Keyring::Charlie).into(), + transfer_to(Keyring::Charlie).into(), + transfer_to(Keyring::Charlie).into(), ], }, ); @@ -336,16 +233,16 @@ mod cfg { validate_ok::( Keyring::Alice, pallet_utility::Call::::batch_all { - calls: vec![transfer_ok::().into()], + calls: vec![transfer_to(Keyring::Bob).into()], }, ); validate_fail::( Keyring::Alice, pallet_utility::Call::::batch_all { calls: vec![ - transfer_fail::().into(), - transfer_fail::().into(), - transfer_fail::().into(), + transfer_to(Keyring::Charlie).into(), + transfer_to(Keyring::Charlie).into(), + transfer_to(Keyring::Charlie).into(), ], }, ); @@ -366,7 +263,7 @@ mod cfg { )] .try_into() .expect("Small enough. qed."), - call: Box::new(transfer_ok::().into()), + call: Box::new(transfer_to(Keyring::Bob).into()), }, ); validate_fail::( @@ -382,8 +279,73 @@ mod cfg { )] .try_into() .expect("Small enough. qed."), - call: Box::new(transfer_fail::().into()), + call: Box::new(transfer_to(Keyring::Charlie).into()), }, ); } } + +mod xcm { + use super::*; + + #[test_runtimes([centrifuge])] + fn restrict_xcm_transfer() { + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 6, + ..transferable_metadata(Some(1000)) + }, + ); + + let mut env = RuntimeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1))) // For fees + .add(genesis::tokens::([(curr.id(), curr.val(3_000))])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) + .storage(), + ); + + env.parachain_state_mut(|| { + assert_ok!( + pallet_transfer_allowlist::Pallet::::add_transfer_allowance( + RawOrigin::Signed(Keyring::Alice.into()).into(), + FilterCurrency::Specific(curr.id()), + RestrictedTransferLocation::Xcm(account_location( + 1, + Some(1001), + Keyring::Alice.id() + )), + ) + ); + + assert_noop!( + pallet_restricted_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + curr.val(1_000), + account_location(1, Some(1001), Keyring::Bob.id()), + WeightLimit::Unlimited, + ), + pallet_transfer_allowlist::Error::::NoAllowanceForDestination + ); + + assert_noop!( + pallet_restricted_xtokens::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + curr.val(1_000), + account_location(1, Some(1001), Keyring::Alice.id()), + WeightLimit::Unlimited, + ), + // But it's ok, we do not care about the xcm transaction in this context + // The xcm transaction is already checked at `cross_transfers.rs` + orml_xtokens::Error::::XcmExecutionFailed + ); + }); + } +} + +mod domain_address { + // TODO +} diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xtransfers.rs index 1eeb7c84ef..e1caeeab7d 100644 --- a/runtime/integration-tests/src/generic/cases/xtransfers.rs +++ b/runtime/integration-tests/src/generic/cases/xtransfers.rs @@ -45,10 +45,10 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { Default::default(), Genesis::default() .add(genesis::tokens::([(curr.id(), curr.val(INITIAL))])) - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), Genesis::default() - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); @@ -87,10 +87,10 @@ fn para_to_sibling_with_native_to_foreign_tokens() { Default::default(), Genesis::default() .add(genesis::balances::(cfg(INITIAL))) - .add(genesis::assets::([(Native, &curr.metadata())])) + .add(genesis::assets::([(Native, curr.metadata())])) .storage(), Genesis::default() - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); @@ -129,10 +129,10 @@ fn para_to_sibling_with_foreign_to_native_tokens() { Default::default(), Genesis::default() .add(genesis::tokens::([(curr.id(), curr.val(INITIAL))])) - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), Genesis::default() - .add(genesis::assets::([(Native, &curr.metadata())])) + .add(genesis::assets::([(Native, curr.metadata())])) .storage(), ); @@ -172,7 +172,7 @@ fn para_from_to_relay_using_relay_native_tokens() { .add(genesis::balances::>(curr.val(INITIAL))) .storage(), Genesis::default() - .add(genesis::assets::([(curr.id(), &curr.metadata())])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), Default::default(), ); diff --git a/runtime/integration-tests/src/generic/utils/currency.rs b/runtime/integration-tests/src/generic/utils/currency.rs index b7484d0cd5..bec217c89e 100644 --- a/runtime/integration-tests/src/generic/utils/currency.rs +++ b/runtime/integration-tests/src/generic/utils/currency.rs @@ -194,6 +194,10 @@ impl CustomCurrency { pub const fn val(&self, amount: u32) -> Balance { amount_pow(amount as Balance, self.1.decimals) } + + pub fn metadata(&self) -> &AssetMetadata { + &self.1 + } } pub fn register_currency( From eeb1dbf46b9f6f9b8002a689ce948015b3d1b1c4 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Fri, 14 Jun 2024 12:52:23 +0200 Subject: [PATCH 12/21] rename file --- .../integration-tests/src/generic/cases/restricted_transfers.rs | 2 +- .../src/generic/cases/{xtransfers.rs => xcm_transfers.rs} | 0 runtime/integration-tests/src/generic/mod.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename runtime/integration-tests/src/generic/cases/{xtransfers.rs => xcm_transfers.rs} (100%) diff --git a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs index cb6f31aa81..39c3b30a92 100644 --- a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs @@ -339,7 +339,7 @@ mod xcm { WeightLimit::Unlimited, ), // But it's ok, we do not care about the xcm transaction in this context - // The xcm transaction is already checked at `cross_transfers.rs` + // The xcm transaction is already checked at `xcm_transfers.rs` orml_xtokens::Error::::XcmExecutionFailed ); }); diff --git a/runtime/integration-tests/src/generic/cases/xtransfers.rs b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs similarity index 100% rename from runtime/integration-tests/src/generic/cases/xtransfers.rs rename to runtime/integration-tests/src/generic/cases/xcm_transfers.rs diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index 13b54573cb..4dc2de2226 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -24,7 +24,7 @@ mod cases { mod precompile; mod proxy; mod restricted_transfers; - mod xtransfers; + mod xcm_transfers; } /// Generate tests for the specified runtimes or all runtimes. From bdee3ed7037d1dccc94840053a5ff6df33475845 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Fri, 14 Jun 2024 14:19:45 +0200 Subject: [PATCH 13/21] restricted ethereum tests simplified and moved to restricted --- .../src/generic/cases/liquidity_pools.rs | 129 +++++++----------- .../src/generic/cases/restricted_transfers.rs | 120 +++++++++++++--- 2 files changed, 154 insertions(+), 95 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 17d1497a7b..c44d6014d3 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -49,7 +49,7 @@ use sp_runtime::{ }; use staging_xcm::{ prelude::XCM_VERSION, - v4::{Junction, Junction::*, Junctions, Junctions::*, Location, NetworkId, WeightLimit}, + v4::{Junction, Junction::*, Junctions::*, Location, NetworkId}, VersionedLocation, }; @@ -5235,109 +5235,84 @@ mod centrifuge { } } - use utils::*; - mod restricted_transfers { use cfg_types::tokens::FilterCurrency; use super::*; - use crate::generic::envs::runtime_env::RuntimeEnv; + use crate::generic::{ + envs::runtime_env::RuntimeEnv, + utils::currency::{default_metadata, CurrencyInfo, CustomCurrency}, + }; - const TRANSFER_AMOUNT: u128 = 10; + const TRANSFER: u32 = 10; + const CHAIN_ID: u64 = 1; + const CONTRACT_ACCOUNT: [u8; 20] = [1; 20]; + + #[test_runtimes(all)] + fn restrict_lp_eth_transfer() { + let pallet_index = T::PalletInfo::index::>(); + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 6, + location: Some(VersionedLocation::V4(Location::new( + 0, + [ + PalletInstance(pallet_index.unwrap() as u8), + GlobalConsensus(NetworkId::Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { + network: None, + key: CONTRACT_ACCOUNT, + }, + ], + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + ..CustomMetadata::default() + }, + ..default_metadata() + }, + ); - #[test_runtimes([centrifuge])] - fn restrict_lp_eth_usdc_lp_transfer() { let mut env = RuntimeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(10))) - .add(orml_tokens::GenesisConfig:: { - balances: vec![( - Keyring::Alice.id(), - LP_ETH_USDC, - T::ExistentialDeposit::get() + lp_eth_usdc(TRANSFER_AMOUNT), - )], - }) + .add(genesis::tokens::([(curr.id(), curr.val(TRANSFER))])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); env.parachain_state_mut(|| { - register_usdc::(T::FudgeHandle::SIBLING_ID); - register_lp_eth_usdc::(); - - assert_ok!(orml_tokens::Pallet::::set_balance( - ::RuntimeOrigin::root(), - ::Sender::get().into(), - USDC, - usdc(1_000), - 0, - )); - - let router = DomainRouter::EthereumXCM(EthereumXCMRouter:: { - router: XCMRouter { - xcm_domain: XcmDomain { - location: Box::new( - Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID)).into(), - ), - ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![ - 38, 0, - ]), - contract_address: H160::from_low_u64_be(11), - max_gas_limit: 700_000, - transact_required_weight_at_most: Default::default(), - overall_weight: Default::default(), - fee_currency: USDC, - fee_amount: usdc(1), - }, - _marker: Default::default(), - }, - _marker: Default::default(), - }); - - assert_ok!( - pallet_liquidity_pools_gateway::Pallet::::set_domain_router( - ::RuntimeOrigin::root(), - Domain::EVM(1), - router, - ) - ); - - let receiver = H160::from_slice( - &>::as_ref(&Keyring::Charlie.id()) - [0..20], - ); - - let domain_address = DomainAddress::EVM(1, receiver.into()); + let curr_contract = DomainAddress::EVM(CHAIN_ID, CONTRACT_ACCOUNT); assert_ok!( pallet_transfer_allowlist::Pallet::::add_transfer_allowance( RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::Specific(LP_ETH_USDC), - RestrictedTransferLocation::Address(domain_address.clone()), + FilterCurrency::Specific(curr.id()), + RestrictedTransferLocation::Address(curr_contract.clone()), ) ); assert_noop!( pallet_liquidity_pools::Pallet::::transfer( RawOrigin::Signed(Keyring::Alice.into()).into(), - LP_ETH_USDC, - DomainAddress::EVM(1, [1u8; 20]), - lp_eth_usdc(TRANSFER_AMOUNT), + curr.id(), + DomainAddress::EVM(CHAIN_ID, [2; 20]), // Not the allowed contract account + curr.val(TRANSFER), ), pallet_transfer_allowlist::Error::::NoAllowanceForDestination ); - let total_issuance_pre = orml_tokens::Pallet::::total_issuance(LP_ETH_USDC); - - assert_ok!(pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - LP_ETH_USDC, - domain_address, - lp_eth_usdc(TRANSFER_AMOUNT), - )); - - assert_eq!( - orml_tokens::Pallet::::total_issuance(LP_ETH_USDC), - total_issuance_pre - lp_eth_usdc(TRANSFER_AMOUNT), + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + curr_contract, + curr.val(TRANSFER), + ), + // But it's ok, we do not care about the router transaction in this context. + // Is already checked at `liquidity_pools.rs` + pallet_liquidity_pools_gateway::Error::::RouterNotFound ); }); } diff --git a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs index 39c3b30a92..6eb8e6ef6d 100644 --- a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs @@ -10,15 +10,23 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{currency_decimals, AccountId, Balance}; +use cfg_primitives::Balance; use cfg_types::{ + domain_address::DomainAddress, locations::RestrictedTransferLocation, - tokens::{AssetMetadata, CurrencyId, FilterCurrency}, + tokens::{ + AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata, FilterCurrency, + }, }; use cumulus_primitives_core::WeightLimit; -use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin}; +use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::PalletInfo}; use runtime_common::remarks::Remark; use sp_runtime::traits::Zero; +use staging_xcm::{ + prelude::XCM_VERSION, + v4::{Junction::*, Junctions::*, Location, NetworkId}, + VersionedLocation, +}; use crate::{ generic::{ @@ -26,7 +34,7 @@ use crate::{ env::Env, envs::runtime_env::RuntimeEnv, utils::{ - currency::{cfg, CurrencyInfo, CustomCurrency}, + currency::{cfg, default_metadata, CurrencyInfo, CustomCurrency}, genesis, genesis::Genesis, xcm::{account_location, transferable_metadata}, @@ -35,11 +43,11 @@ use crate::{ utils::accounts::Keyring, }; -const TRANSFER_AMOUNT: u32 = 100; - mod local { use super::*; + const TRANSFER_AMOUNT: u32 = 100; + fn setup(filter: FilterCurrency) -> RuntimeEnv { let mut env = RuntimeEnv::::from_parachain_storage( Genesis::default() @@ -288,20 +296,23 @@ mod local { mod xcm { use super::*; - #[test_runtimes([centrifuge])] + const TRANSFER: u32 = 100; + const PARA_ID: u32 = 1000; + + #[test_runtimes(all)] fn restrict_xcm_transfer() { let curr = CustomCurrency( CurrencyId::ForeignAsset(1), AssetMetadata { decimals: 6, - ..transferable_metadata(Some(1000)) + ..transferable_metadata(Some(PARA_ID)) }, ); let mut env = RuntimeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1))) // For fees - .add(genesis::tokens::([(curr.id(), curr.val(3_000))])) + .add(genesis::tokens::([(curr.id(), curr.val(TRANSFER))])) .add(genesis::assets::([(curr.id(), curr.metadata())])) .storage(), ); @@ -313,7 +324,7 @@ mod xcm { FilterCurrency::Specific(curr.id()), RestrictedTransferLocation::Xcm(account_location( 1, - Some(1001), + Some(PARA_ID), Keyring::Alice.id() )), ) @@ -323,8 +334,8 @@ mod xcm { pallet_restricted_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Alice.into()).into(), curr.id(), - curr.val(1_000), - account_location(1, Some(1001), Keyring::Bob.id()), + curr.val(TRANSFER), + account_location(1, Some(PARA_ID), Keyring::Bob.id()), WeightLimit::Unlimited, ), pallet_transfer_allowlist::Error::::NoAllowanceForDestination @@ -334,18 +345,91 @@ mod xcm { pallet_restricted_xtokens::Pallet::::transfer( RawOrigin::Signed(Keyring::Alice.into()).into(), curr.id(), - curr.val(1_000), - account_location(1, Some(1001), Keyring::Alice.id()), + curr.val(TRANSFER), + account_location(1, Some(PARA_ID), Keyring::Alice.id()), WeightLimit::Unlimited, ), - // But it's ok, we do not care about the xcm transaction in this context - // The xcm transaction is already checked at `xcm_transfers.rs` + // But it's ok, we do not care about the xcm transaction in this context. + // It is already checked at `xcm_transfers.rs` orml_xtokens::Error::::XcmExecutionFailed ); }); } } -mod domain_address { - // TODO +mod eth_address { + use super::*; + + const TRANSFER: u32 = 10; + const CHAIN_ID: u64 = 1; + const CONTRACT_ACCOUNT: [u8; 20] = [1; 20]; + + #[test_runtimes(all)] + fn restrict_lp_eth_transfer() { + let pallet_index = T::PalletInfo::index::>(); + let curr = CustomCurrency( + CurrencyId::ForeignAsset(1), + AssetMetadata { + decimals: 6, + location: Some(VersionedLocation::V4(Location::new( + 0, + [ + PalletInstance(pallet_index.unwrap() as u8), + GlobalConsensus(NetworkId::Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { + network: None, + key: CONTRACT_ACCOUNT, + }, + ], + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + ..CustomMetadata::default() + }, + ..default_metadata() + }, + ); + + let mut env = RuntimeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(10))) + .add(genesis::tokens::([(curr.id(), curr.val(TRANSFER))])) + .add(genesis::assets::([(curr.id(), curr.metadata())])) + .storage(), + ); + + env.parachain_state_mut(|| { + let curr_contract = DomainAddress::EVM(CHAIN_ID, CONTRACT_ACCOUNT); + + assert_ok!( + pallet_transfer_allowlist::Pallet::::add_transfer_allowance( + RawOrigin::Signed(Keyring::Alice.into()).into(), + FilterCurrency::Specific(curr.id()), + RestrictedTransferLocation::Address(curr_contract.clone()), + ) + ); + + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + DomainAddress::EVM(CHAIN_ID, [2; 20]), // Not the allowed contract account + curr.val(TRANSFER), + ), + pallet_transfer_allowlist::Error::::NoAllowanceForDestination + ); + + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(Keyring::Alice.into()).into(), + curr.id(), + curr_contract, + curr.val(TRANSFER), + ), + // But it's ok, we do not care about the router transaction in this context. + // Is already checked at `liquidity_pools.rs` + pallet_liquidity_pools_gateway::Error::::RouterNotFound + ); + }); + } } From 0c3bb4386e922425682d8b1755cbeaf6d681f164 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Fri, 14 Jun 2024 14:29:18 +0200 Subject: [PATCH 14/21] cleaning warnings --- .../src/generic/cases/liquidity_pools.rs | 8567 ++++++++--------- .../src/generic/cases/restricted_transfers.rs | 3 +- .../src/generic/cases/xcm_transfers.rs | 26 +- .../src/generic/envs/fudge_env.rs | 2 +- .../src/generic/utils/xcm.rs | 41 +- 5 files changed, 4059 insertions(+), 4580 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index c44d6014d3..cef47d70ef 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -10,12 +10,10 @@ use cfg_types::{ domain_address::{Domain, DomainAddress}, fixed_point::{Quantity, Ratio}, investments::{InvestCollection, InvestmentAccount, RedeemCollection}, - locations::RestrictedTransferLocation, orders::FulfillmentWithPrice, permissions::{PermissionScope, PoolRole, Role}, pools::TrancheMetadata, tokens::{AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata}, - xcm::XcmMetadata, }; use frame_support::{ assert_noop, assert_ok, @@ -35,21 +33,17 @@ use pallet_liquidity_pools::Message; use pallet_liquidity_pools_gateway::{Call as LiquidityPoolsGatewayCall, GatewayOrigin}; use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheType}; use polkadot_core_primitives::BlakeTwo256; -use polkadot_parachain_primitives::primitives::Id; use runtime_common::{ account_conversion::AccountConverter, foreign_investments::IdentityPoolCurrencyConverter, - xcm::general_key, xcm_fees::default_per_second, + xcm::general_key, }; use sp_core::{Get, H160, U256}; use sp_runtime::{ - traits::{ - AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, Hash, One, StaticLookup, Zero, - }, - BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, WeakBoundedVec, + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, Hash, One, Zero}, + BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, }; use staging_xcm::{ - prelude::XCM_VERSION, - v4::{Junction, Junction::*, Junctions::*, Location, NetworkId}, + v4::{Junction, Junction::*, Location, NetworkId}, VersionedLocation, }; @@ -57,7 +51,7 @@ use crate::{ generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, utils::{ democracy::execute_via_democracy, genesis, genesis::Genesis, xcm::enable_para_to_sibling_communication, @@ -74,50 +68,35 @@ pub const USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); pub const AUSD_ED: Balance = 1_000_000_000; pub const USDT_ED: Balance = 10_000; -mod utils { - use super::*; - - pub fn parachain_account(id: u32) -> AccountId { - polkadot_parachain_primitives::primitives::Sibling::from(id).into_account_truncating() - } - - pub fn xcm_metadata(transferability: CrossChainTransferability) -> Option { - match transferability { - CrossChainTransferability::Xcm(x) => Some(x), - _ => None, - } - } - - pub fn setup_usdc_xcm(env: &mut FudgeEnv) { - env.parachain_state_mut(|| { - // Set the XCM version used when sending XCM messages to USDC parachain. - assert_ok!(pallet_xcm::Pallet::::force_xcm_version( - ::RuntimeOrigin::root(), - Box::new(Location::new(1, Junction::Parachain(1000))), - XCM_VERSION, - )); - }); +pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(4); +pub const GLMR_ED: Balance = 1_000_000; +pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; +pub const POOL_ADMIN: Keyring = Keyring::Bob; +pub const POOL_ID: PoolId = 42; +pub const MOONBEAM_EVM_CHAIN_ID: u64 = 1284; +pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; +pub const DEFAULT_VALIDITY: Seconds = 2555583502; +pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); +pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, DEFAULT_EVM_ADDRESS_MOONBEAM); +pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); + +pub type LiquidityPoolMessage = Message; - 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(1000), - 10, - 1024, - )); +mod utils { + use cfg_types::oracles::OracleKey; + use frame_support::weights::Weight; + use runtime_common::oracle::Feeder; - assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< - FudgeRelayRuntime, - >::force_process_hrmp_open( - as frame_system::Config>::RuntimeOrigin::root(), - 2, - )); - }); + use super::*; - env.pass(Blocks::ByNumber(1)); + /// Creates a new pool for the given id with + /// * BOB as admin and depositor + /// * Two tranches + /// * AUSD as pool currency with max reserve 10k. + pub fn create_ausd_pool(pool_id: u64) { + create_currency_pool::(pool_id, AUSD_CURRENCY_ID, decimals(currency_decimals::AUSD)) } pub fn register_ausd() { @@ -147,38 +126,14 @@ mod utils { )); } - pub fn ausd(amount: Balance) -> Balance { - amount * decimals(currency_decimals::AUSD) - } - - pub fn ausd_fee() -> Balance { - fee(currency_decimals::AUSD) - } - pub fn cfg(amount: Balance) -> Balance { amount * decimals(currency_decimals::NATIVE) } - pub fn cfg_fee() -> Balance { - fee(currency_decimals::NATIVE) - } - pub fn decimals(decimals: u32) -> Balance { 10u128.saturating_pow(decimals) } - pub fn fee(decimals: u32) -> Balance { - calc_fee(default_per_second(decimals)) - } - - 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 set_domain_router_call( domain: Domain, router: DomainRouter, @@ -193,63 +148,26 @@ mod utils { pub fn remove_instance_call(instance: DomainAddress) -> T::RuntimeCallExt { LiquidityPoolsGatewayCall::remove_instance { instance }.into() } -} - -use utils::*; -mod development { - use super::*; - - pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(4); - pub const GLMR_ED: Balance = 1_000_000; - pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; - pub const POOL_ADMIN: Keyring = Keyring::Bob; - pub const POOL_ID: PoolId = 42; - pub const MOONBEAM_EVM_CHAIN_ID: u64 = 1284; - pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; - pub const DEFAULT_VALIDITY: Seconds = 2555583502; - pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); - pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = - DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, DEFAULT_EVM_ADDRESS_MOONBEAM); - pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = - DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); - - pub type LiquidityPoolMessage = Message; - - mod utils { - use cfg_types::oracles::OracleKey; - use frame_support::weights::Weight; - use runtime_common::oracle::Feeder; - - use super::*; - - /// Creates a new pool for the given id with - /// * BOB as admin and depositor - /// * Two tranches - /// * AUSD as pool currency with max reserve 10k. - pub fn create_ausd_pool(pool_id: u64) { - create_currency_pool::(pool_id, AUSD_CURRENCY_ID, decimals(currency_decimals::AUSD)) - } - - /// Creates a new pool for for the given id with the provided currency. - /// * BOB as admin and depositor - /// * Two tranches - /// * The given `currency` as pool currency with of - /// `currency_decimals`. - pub fn create_currency_pool( - pool_id: u64, - currency_id: CurrencyId, - currency_decimals: Balance, - ) { - assert_ok!(pallet_pool_system::Pallet::::create( - POOL_ADMIN.into(), - POOL_ADMIN.into(), - pool_id, - vec![ - TrancheInput { - tranche_type: TrancheType::Residual, - seniority: None, - metadata: TrancheMetadata { + /// Creates a new pool for for the given id with the provided currency. + /// * BOB as admin and depositor + /// * Two tranches + /// * The given `currency` as pool currency with of `currency_decimals`. + pub fn create_currency_pool( + pool_id: u64, + currency_id: CurrencyId, + currency_decimals: Balance, + ) { + assert_ok!(pallet_pool_system::Pallet::::create( + POOL_ADMIN.into(), + POOL_ADMIN.into(), + pool_id, + vec![ + TrancheInput { + tranche_type: TrancheType::Residual, + seniority: None, + metadata: + TrancheMetadata { // NOTE: For now, we have to set these metadata fields of the first // tranche to be convertible to the 32-byte size expected by the // liquidity pools AddTranche message. @@ -266,374 +184,269 @@ mod development { >::try_from("TrNcH".as_bytes().to_vec()) .expect("Can create BoundedVec for token symbol"), } + }, + TrancheInput { + tranche_type: TrancheType::NonResidual { + interest_rate_per_sec: One::one(), + min_risk_buffer: Perquintill::from_percent(10), }, - TrancheInput { - tranche_type: TrancheType::NonResidual { - interest_rate_per_sec: One::one(), - min_risk_buffer: Perquintill::from_percent(10), - }, - seniority: None, - metadata: TrancheMetadata { - token_name: BoundedVec::default(), - token_symbol: BoundedVec::default(), - } + seniority: None, + metadata: TrancheMetadata { + token_name: BoundedVec::default(), + token_symbol: BoundedVec::default(), } - ], - currency_id, - currency_decimals, - // No pool fees per default - vec![] - )); - } + } + ], + currency_id, + currency_decimals, + // No pool fees per default + vec![] + )); + } - pub fn register_glmr() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: GLMR_ED, - location: Some(VersionedLocation::V4(Location::new( - 1, - [Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])], - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; + pub fn register_glmr() { + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: BoundedVec::default(), + symbol: BoundedVec::default(), + existential_deposit: GLMR_ED, + location: Some(VersionedLocation::V4(Location::new( + 1, + [Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])], + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(GLMR_CURRENCY_ID) - )); - } + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(GLMR_CURRENCY_ID) + )); + } - pub fn set_test_domain_router( - evm_chain_id: u64, - xcm_domain_location: VersionedLocation, - currency_id: CurrencyId, - ) { - let ethereum_xcm_router = EthereumXCMRouter:: { - router: XCMRouter { - xcm_domain: XcmDomain { - location: Box::new(xcm_domain_location), - ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), - contract_address: H160::from(DEFAULT_EVM_ADDRESS_MOONBEAM), - max_gas_limit: 500_000, - transact_required_weight_at_most: Weight::from_parts( - 12530000000, - DEFAULT_PROOF_SIZE.saturating_div(2), - ), - overall_weight: Weight::from_parts(15530000000, DEFAULT_PROOF_SIZE), - fee_currency: currency_id, - // 0.2 token - fee_amount: 200000000000000000, - }, - _marker: Default::default(), + pub fn set_test_domain_router( + evm_chain_id: u64, + xcm_domain_location: VersionedLocation, + currency_id: CurrencyId, + ) { + let ethereum_xcm_router = EthereumXCMRouter:: { + router: XCMRouter { + xcm_domain: XcmDomain { + location: Box::new(xcm_domain_location), + ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), + contract_address: H160::from(DEFAULT_EVM_ADDRESS_MOONBEAM), + max_gas_limit: 500_000, + transact_required_weight_at_most: Weight::from_parts( + 12530000000, + DEFAULT_PROOF_SIZE.saturating_div(2), + ), + overall_weight: Weight::from_parts(15530000000, DEFAULT_PROOF_SIZE), + fee_currency: currency_id, + // 0.2 token + fee_amount: 200000000000000000, }, _marker: Default::default(), - }; - - let domain_router = DomainRouter::EthereumXCM(ethereum_xcm_router); - let domain = Domain::EVM(evm_chain_id); - - assert_ok!( - pallet_liquidity_pools_gateway::Pallet::::set_domain_router( - ::RuntimeOrigin::root(), - domain, - domain_router, - ) - ); - } - - pub fn default_tranche_id(pool_id: u64) -> TrancheId { - let pool_details = - pallet_pool_system::pallet::Pool::::get(pool_id).expect("Pool should exist"); - pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists") - } - - /// Returns a `VersionedLocation` that can be converted into - /// `LiquidityPoolsWrappedToken` which is required for cross chain asset - /// registration and transfer. - pub fn liquidity_pools_transferable_multilocation( - chain_id: u64, - address: [u8; 20], - ) -> VersionedLocation { - VersionedLocation::V4(Location::new( - 0, - [ - PalletInstance( - ::PalletInfo::index::< - pallet_liquidity_pools::Pallet, - >() - .expect("LiquidityPools should have pallet index") - .saturated_into(), - ), - GlobalConsensus(NetworkId::Ethereum { chain_id }), - AccountKey20 { - network: None, - key: address, - }, - ], - )) - } + }, + _marker: Default::default(), + }; - /// Enables `LiquidityPoolsTransferable` in the custom asset metadata - /// for the given currency_id. - /// - /// NOTE: Sets the location to the `MOONBEAM_EVM_CHAIN_ID` with dummy - /// address as the location is required for LiquidityPoolsWrappedToken - /// conversions. - pub fn enable_liquidity_pool_transferability( - currency_id: CurrencyId, - ) { - let metadata = orml_asset_registry::Metadata::::get(currency_id) - .expect("Currency should be registered"); - let location = Some(Some(liquidity_pools_transferable_multilocation::( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))); + let domain_router = DomainRouter::EthereumXCM(ethereum_xcm_router); + let domain = Domain::EVM(evm_chain_id); - assert_ok!(orml_asset_registry::Pallet::::update_asset( + assert_ok!( + pallet_liquidity_pools_gateway::Pallet::::set_domain_router( ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - location, - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - ..metadata.additional - }) - )); - } - - pub fn setup_test(env: &mut FudgeEnv) { - env.parachain_state_mut(|| { - register_ausd::(); - register_glmr::(); - - assert_ok!(orml_tokens::Pallet::::set_balance( - ::RuntimeOrigin::root(), - ::Sender::get().into(), - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - 0, - )); - - set_test_domain_router::( - MOONBEAM_EVM_CHAIN_ID, - Location::new(1, Junction::Parachain(T::FudgeHandle::SIBLING_ID)).into(), - GLMR_CURRENCY_ID, - ); - }); - } - - /// Returns the derived general currency index. - /// - /// Throws if the provided currency_id is not - /// `CurrencyId::ForeignAsset(id)`. - pub fn general_currency_index(currency_id: CurrencyId) -> u128 { - pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) - .expect("ForeignAsset should convert into u128") - } + domain, + domain_router, + ) + ); + } - /// Returns the investment_id of the given pool and tranche ids. - pub fn investment_id( - pool_id: u64, - tranche_id: TrancheId, - ) -> cfg_types::tokens::TrancheCurrency { - ::TrancheCurrency::generate(pool_id, tranche_id) - } + pub fn default_tranche_id(pool_id: u64) -> TrancheId { + let pool_details = + pallet_pool_system::pallet::Pool::::get(pool_id).expect("Pool should exist"); + pool_details + .tranches + .tranche_id(TrancheLoc::Index(0)) + .expect("Tranche at index 0 exists") + } - pub fn default_investment_id( - ) -> cfg_types::tokens::TrancheCurrency { - ::TrancheCurrency::generate( - POOL_ID, - default_tranche_id::(POOL_ID), - ) - } + /// Returns a `VersionedLocation` that can be converted into + /// `LiquidityPoolsWrappedToken` which is required for cross chain asset + /// registration and transfer. + pub fn liquidity_pools_transferable_multilocation( + chain_id: u64, + address: [u8; 20], + ) -> VersionedLocation { + VersionedLocation::V4(Location::new( + 0, + [ + PalletInstance( + ::PalletInfo::index::< + pallet_liquidity_pools::Pallet, + >() + .expect("LiquidityPools should have pallet index") + .saturated_into(), + ), + GlobalConsensus(NetworkId::Ethereum { chain_id }), + AccountKey20 { + network: None, + key: address, + }, + ], + )) + } - pub fn default_order_id(investor: &AccountId) -> OrderId { - let default_swap_id = ( - default_investment_id::(), - pallet_foreign_investments::Action::Investment, - ); - pallet_swaps::Pallet::::order_id(&investor, default_swap_id) - .expect("Swap order exists; qed") - } + /// Enables `LiquidityPoolsTransferable` in the custom asset metadata + /// for the given currency_id. + /// + /// NOTE: Sets the location to the `MOONBEAM_EVM_CHAIN_ID` with dummy + /// address as the location is required for LiquidityPoolsWrappedToken + /// conversions. + pub fn enable_liquidity_pool_transferability( + currency_id: CurrencyId, + ) { + let metadata = orml_asset_registry::Metadata::::get(currency_id) + .expect("Currency should be registered"); + let location = Some(Some(liquidity_pools_transferable_multilocation::( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))); + + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + location, + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + ..metadata.additional + }) + )); + } - /// Returns the default investment account derived from the - /// `DEFAULT_POOL_ID` and its default tranche. - pub fn default_investment_account() -> AccountId { - InvestmentAccount { - investment_id: default_investment_id::(), - } - .into_account_truncating() - } + pub fn setup_test(env: &mut FudgeEnv) { + env.parachain_state_mut(|| { + register_ausd::(); + register_glmr::(); - pub fn fulfill_swap_into_pool( - pool_id: u64, - swap_order_id: u64, - amount_pool: Balance, - amount_foreign: Balance, - trader: AccountId, - ) { - let pool_currency: CurrencyId = pallet_pool_system::Pallet::::currency_for(pool_id) - .expect("Pool existence checked already"); - assert_ok!(orml_tokens::Pallet::::mint_into( - pool_currency, - &trader, - amount_pool - )); - assert_ok!(pallet_order_book::Pallet::::fill_order( - RawOrigin::Signed(trader.clone()).into(), - swap_order_id, - amount_foreign + assert_ok!(orml_tokens::Pallet::::set_balance( + ::RuntimeOrigin::root(), + ::Sender::get().into(), + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + 0, )); - } - - /// Sets up required permissions for the investor and executes an - /// initial investment via LiquidityPools by executing - /// `IncreaseInvestOrder`. - /// - /// Assumes `setup_pre_requirements` and - /// `investments::create_currency_pool` to have been called - /// beforehand - pub fn do_initial_increase_investment( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let pool_currency: CurrencyId = pallet_pool_system::Pallet::::currency_for(pool_id) - .expect("Pool existence checked already"); - // Mock incoming increase invest message - let msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount, - }; + set_test_domain_router::( + MOONBEAM_EVM_CHAIN_ID, + Location::new(1, Junction::Parachain(T::FudgeHandle::SIBLING_ID)).into(), + GLMR_CURRENCY_ID, + ); + }); + } - // Should fail if investor does not have investor role yet - // However, failure is async for foreign currencies as part of updating the - // investment after the swap was fulfilled - if currency_id == pool_currency { - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - ), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - } + /// Returns the derived general currency index. + /// + /// Throws if the provided currency_id is not + /// `CurrencyId::ForeignAsset(id)`. + pub fn general_currency_index(currency_id: CurrencyId) -> u128 { + pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) + .expect("ForeignAsset should convert into u128") + } - // Make investor the MembersListAdmin of this Pool - if !pallet_permissions::Pallet::::has( - PermissionScope::Pool(pool_id), - investor.clone(), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id::(pool_id), - DEFAULT_VALIDITY, - )), - ) { - crate::generic::utils::pool::give_role::( - investor.clone(), - pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), DEFAULT_VALIDITY), - ); - } + /// Returns the investment_id of the given pool and tranche ids. + pub fn investment_id( + pool_id: u64, + tranche_id: TrancheId, + ) -> cfg_types::tokens::TrancheCurrency { + ::TrancheCurrency::generate(pool_id, tranche_id) + } - let amount_before = - orml_tokens::Pallet::::balance(currency_id, &default_investment_account::()); - let final_amount = amount_before - .ensure_add(amount) - .expect("Should not overflow when incrementing amount"); + pub fn default_investment_id() -> cfg_types::tokens::TrancheCurrency + { + ::TrancheCurrency::generate( + POOL_ID, + default_tranche_id::(POOL_ID), + ) + } - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + pub fn default_order_id(investor: &AccountId) -> OrderId { + let default_swap_id = ( + default_investment_id::(), + pallet_foreign_investments::Action::Investment, + ); + pallet_swaps::Pallet::::order_id(&investor, default_swap_id) + .expect("Swap order exists; qed") + } - if currency_id == pool_currency { - // Verify investment was transferred into investment account - assert_eq!( - orml_tokens::Pallet::::balance( - currency_id, - &default_investment_account::() - ), - final_amount - ); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount, - } - .into() - })); - } + /// Returns the default investment account derived from the + /// `DEFAULT_POOL_ID` and its default tranche. + pub fn default_investment_account() -> AccountId { + InvestmentAccount { + investment_id: default_investment_id::(), } + .into_account_truncating() + } - /// Sets up required permissions for the investor and executes an - /// initial redemption via LiquidityPools by executing - /// `IncreaseRedeemOrder`. - /// - /// Assumes `setup_pre_requirements` and - /// `investments::create_currency_pool` to have been called - /// beforehand. - /// - /// NOTE: Mints exactly the redeeming amount of tranche tokens. - pub fn do_initial_increase_redemption( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - // Fund `DomainLocator` account of origination domain as redeemed tranche tokens - // are transferred from this account instead of minting - assert_ok!(orml_tokens::Pallet::::mint_into( - default_investment_id::().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount - )); - - // Verify redemption has not been made yet - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &default_investment_account::(), - ), - 0 - ); - assert_eq!( - orml_tokens::Pallet::::balance(default_investment_id::().into(), &investor), - 0 - ); + pub fn fulfill_swap_into_pool( + pool_id: u64, + swap_order_id: u64, + amount_pool: Balance, + amount_foreign: Balance, + trader: AccountId, + ) { + let pool_currency: CurrencyId = pallet_pool_system::Pallet::::currency_for(pool_id) + .expect("Pool existence checked already"); + assert_ok!(orml_tokens::Pallet::::mint_into( + pool_currency, + &trader, + amount_pool + )); + assert_ok!(pallet_order_book::Pallet::::fill_order( + RawOrigin::Signed(trader.clone()).into(), + swap_order_id, + amount_foreign + )); + } - // Mock incoming increase invest message - let msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount, - }; + /// Sets up required permissions for the investor and executes an + /// initial investment via LiquidityPools by executing + /// `IncreaseInvestOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand + pub fn do_initial_increase_investment( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let pool_currency: CurrencyId = pallet_pool_system::Pallet::::currency_for(pool_id) + .expect("Pool existence checked already"); + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount, + }; - // Should fail if investor does not have investor role yet + // Should fail if investor does not have investor role yet + // However, failure is async for foreign currencies as part of updating the + // investment after the swap was fulfilled + if currency_id == pool_currency { assert_noop!( pallet_liquidity_pools::Pallet::::submit( DEFAULT_DOMAIN_ADDRESS_MOONBEAM, @@ -641,3391 +454,2252 @@ mod development { ), DispatchError::Other("Account does not have the TrancheInvestor permission.") ); + } - // Make investor the MembersListAdmin of this Pool + // Make investor the MembersListAdmin of this Pool + if !pallet_permissions::Pallet::::has( + PermissionScope::Pool(pool_id), + investor.clone(), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id::(pool_id), + DEFAULT_VALIDITY, + )), + ) { crate::generic::utils::pool::give_role::( investor.clone(), pool_id, PoolRole::TrancheInvestor(default_tranche_id::(pool_id), DEFAULT_VALIDITY), ); + } - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + let amount_before = + orml_tokens::Pallet::::balance(currency_id, &default_investment_account::()); + let final_amount = amount_before + .ensure_add(amount) + .expect("Should not overflow when incrementing amount"); - // Verify redemption was transferred into investment account - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &default_investment_account::(), - ), - amount - ); - assert_eq!( - orml_tokens::Pallet::::balance(default_investment_id::().into(), &investor), - 0 - ); - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &AccountConverter::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) - ), - 0 - ); - assert_eq!( - frame_system::Pallet::::events() - .iter() - .last() - .unwrap() - .event, - pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor, - amount - } - .into() - ); + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Verify order id is 0 + if currency_id == pool_currency { + // Verify investment was transferred into investment account assert_eq!( - pallet_investments::Pallet::::redeem_order_id(investment_id::( - pool_id, - default_tranche_id::(pool_id) - )), - 0 + orml_tokens::Pallet::::balance(currency_id, &default_investment_account::()), + final_amount ); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount, + } + .into() + })); } + } - /// Register USDT in the asset registry and enable LiquidityPools cross - /// chain transferability. - /// - /// NOTE: Assumes to be executed within an externalities environment. - fn register_usdt() { - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: USDT_ED, - location: Some(VersionedLocation::V4(Location::new( - 1, - [Parachain(1000), PalletInstance(50), GeneralIndex(1984)], - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - pool_currency: true, - ..CustomMetadata::default() - }, - }; + /// Sets up required permissions for the investor and executes an + /// initial redemption via LiquidityPools by executing + /// `IncreaseRedeemOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand. + /// + /// NOTE: Mints exactly the redeeming amount of tranche tokens. + pub fn do_initial_increase_redemption( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + // Fund `DomainLocator` account of origination domain as redeemed tranche tokens + // are transferred from this account instead of minting + assert_ok!(orml_tokens::Pallet::::mint_into( + default_investment_id::().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount + )); - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(USDT_CURRENCY_ID) - )); - } + // Verify redemption has not been made yet + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &default_investment_account::(), + ), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::balance(default_investment_id::().into(), &investor), + 0 + ); + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount, + }; - /// Registers USDT currency, adds bidirectional trading pairs with - /// conversion ratio one and returns the amount in foreign denomination. - pub fn enable_usdt_trading( - pool_currency: CurrencyId, - amount_pool_denominated: Balance, - enable_lp_transferability: bool, - enable_foreign_to_pool_pair: bool, - enable_pool_to_foreign_pair: bool, - ) -> Balance { - register_usdt::(); - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let amount_foreign_denominated: u128 = - IdentityPoolCurrencyConverter::>::stable_to_stable( - foreign_currency, - pool_currency, - amount_pool_denominated, - ) - .unwrap(); + // Should fail if investor does not have investor role yet + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + ), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + + // Make investor the MembersListAdmin of this Pool + crate::generic::utils::pool::give_role::( + investor.clone(), + pool_id, + PoolRole::TrancheInvestor(default_tranche_id::(pool_id), DEFAULT_VALIDITY), + ); + + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - if enable_lp_transferability { - enable_liquidity_pool_transferability::(foreign_currency); + // Verify redemption was transferred into investment account + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &default_investment_account::(), + ), + amount + ); + assert_eq!( + orml_tokens::Pallet::::balance(default_investment_id::().into(), &investor), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &AccountConverter::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) + ), + 0 + ); + assert_eq!( + frame_system::Pallet::::events() + .iter() + .last() + .unwrap() + .event, + pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor, + amount } + .into() + ); - assert_ok!(pallet_order_book::Pallet::::set_market_feeder( - ::RuntimeOrigin::root(), - Feeder::root(), - )); - crate::generic::utils::oracle::update_feeders::( - POOL_ADMIN.id(), - POOL_ID, - [Feeder::root()], - ); + // Verify order id is 0 + assert_eq!( + pallet_investments::Pallet::::redeem_order_id(investment_id::( + pool_id, + default_tranche_id::(pool_id) + )), + 0 + ); + } - if enable_foreign_to_pool_pair { - crate::generic::utils::oracle::feed_from_root::( - OracleKey::ConversionRatio(foreign_currency, pool_currency), - Ratio::one(), - ); - } - if enable_pool_to_foreign_pair { - crate::generic::utils::oracle::feed_from_root::( - OracleKey::ConversionRatio(pool_currency, foreign_currency), - Ratio::one(), - ); - } + /// Register USDT in the asset registry and enable LiquidityPools cross + /// chain transferability. + /// + /// NOTE: Assumes to be executed within an externalities environment. + fn register_usdt() { + let meta: AssetMetadata = AssetMetadata { + decimals: 6, + name: BoundedVec::default(), + symbol: BoundedVec::default(), + existential_deposit: USDT_ED, + location: Some(VersionedLocation::V4(Location::new( + 1, + [Parachain(1000), PalletInstance(50), GeneralIndex(1984)], + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + pool_currency: true, + ..CustomMetadata::default() + }, + }; + + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + meta, + Some(USDT_CURRENCY_ID) + )); + } + + /// Registers USDT currency, adds bidirectional trading pairs with + /// conversion ratio one and returns the amount in foreign denomination. + pub fn enable_usdt_trading( + pool_currency: CurrencyId, + amount_pool_denominated: Balance, + enable_lp_transferability: bool, + enable_foreign_to_pool_pair: bool, + enable_pool_to_foreign_pair: bool, + ) -> Balance { + register_usdt::(); + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::>::stable_to_stable( + foreign_currency, + pool_currency, + amount_pool_denominated, + ) + .unwrap(); - amount_foreign_denominated + if enable_lp_transferability { + enable_liquidity_pool_transferability::(foreign_currency); } - pub fn get_council_members() -> Vec { - vec![Keyring::Alice, Keyring::Bob, Keyring::Charlie] + assert_ok!(pallet_order_book::Pallet::::set_market_feeder( + ::RuntimeOrigin::root(), + Feeder::root(), + )); + crate::generic::utils::oracle::update_feeders::( + POOL_ADMIN.id(), + POOL_ID, + [Feeder::root()], + ); + + if enable_foreign_to_pool_pair { + crate::generic::utils::oracle::feed_from_root::( + OracleKey::ConversionRatio(foreign_currency, pool_currency), + Ratio::one(), + ); } + if enable_pool_to_foreign_pair { + crate::generic::utils::oracle::feed_from_root::( + OracleKey::ConversionRatio(pool_currency, foreign_currency), + Ratio::one(), + ); + } + + amount_foreign_denominated } - use utils::*; + pub fn get_council_members() -> Vec { + vec![Keyring::Alice, Keyring::Bob, Keyring::Charlie] + } +} - mod add_allow_upgrade { - use cfg_types::tokens::LiquidityPoolsWrappedToken; +use utils::*; - use super::*; +mod add_allow_upgrade { + use cfg_types::tokens::LiquidityPoolsWrappedToken; - #[test_runtimes([development])] - fn add_pool() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), - ); + use super::*; - setup_test(&mut env); + #[test_runtimes([development])] + fn add_pool() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; + setup_test(&mut env); - // Verify that the pool must exist before we can call - // pallet_liquidity_pools::Pallet::::add_pool - assert_noop!( - pallet_liquidity_pools::Pallet::::add_pool( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; - // Now create the pool - create_ausd_pool::(pool_id); + // Verify that the pool must exist before we can call + // pallet_liquidity_pools::Pallet::::add_pool + assert_noop!( + pallet_liquidity_pools::Pallet::::add_pool( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::PoolNotFound + ); - // Verify ALICE can't call `add_pool` given she is not the `PoolAdmin` - assert_noop!( - pallet_liquidity_pools::Pallet::::add_pool( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); + // Now create the pool + create_ausd_pool::(pool_id); - // Verify that it works if it's BOB calling it (the pool admin) - assert_ok!(pallet_liquidity_pools::Pallet::::add_pool( - RawOrigin::Signed(POOL_ADMIN.into()).into(), + // Verify ALICE can't call `add_pool` given she is not the `PoolAdmin` + assert_noop!( + pallet_liquidity_pools::Pallet::::add_pool( + RawOrigin::Signed(Keyring::Alice.into()).into(), pool_id, Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - )); - }); - } - - #[test_runtimes([development])] - fn add_tranche() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + ), + pallet_liquidity_pools::Error::::NotPoolAdmin ); - setup_test(&mut env); + // Verify that it works if it's BOB calling it (the pool admin) + assert_ok!(pallet_liquidity_pools::Pallet::::add_pool( + RawOrigin::Signed(POOL_ADMIN.into()).into(), + pool_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + )); + }); + } - env.parachain_state_mut(|| { - // Now create the pool - let pool_id = POOL_ID; - create_ausd_pool::(pool_id); + #[test_runtimes([development])] + fn add_tranche() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - // Verify we can't call pallet_liquidity_pools::Pallet::::add_tranche with a - // non-existing tranche_id - let nonexistent_tranche = [71u8; 16]; + setup_test(&mut env); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_tranche( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - nonexistent_tranche, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::TrancheNotFound - ); - let tranche_id = default_tranche_id::(pool_id); + env.parachain_state_mut(|| { + // Now create the pool + let pool_id = POOL_ID; + create_ausd_pool::(pool_id); - // Verify ALICE can't call `add_tranche` given she is not the `PoolAdmin` - assert_noop!( - pallet_liquidity_pools::Pallet::::add_tranche( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - tranche_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); + // Verify we can't call pallet_liquidity_pools::Pallet::::add_tranche with a + // non-existing tranche_id + let nonexistent_tranche = [71u8; 16]; - // Finally, verify we can call pallet_liquidity_pools::Pallet::::add_tranche - // successfully when called by the PoolAdmin with the right pool + tranche id - // pair. - assert_ok!(pallet_liquidity_pools::Pallet::::add_tranche( - RawOrigin::Signed(POOL_ADMIN.into()).into(), + assert_noop!( + pallet_liquidity_pools::Pallet::::add_tranche( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + nonexistent_tranche, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheNotFound + ); + let tranche_id = default_tranche_id::(pool_id); + + // Verify ALICE can't call `add_tranche` given she is not the `PoolAdmin` + assert_noop!( + pallet_liquidity_pools::Pallet::::add_tranche( + RawOrigin::Signed(Keyring::Alice.into()).into(), pool_id, tranche_id, Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - )); + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); - // Edge case: Should throw if tranche exists but metadata does not exist - let tranche_currency_id = CurrencyId::Tranche(pool_id, tranche_id); + // Finally, verify we can call pallet_liquidity_pools::Pallet::::add_tranche + // successfully when called by the PoolAdmin with the right pool + tranche id + // pair. + assert_ok!(pallet_liquidity_pools::Pallet::::add_tranche( + RawOrigin::Signed(POOL_ADMIN.into()).into(), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + )); - orml_asset_registry::Metadata::::remove(tranche_currency_id); + // Edge case: Should throw if tranche exists but metadata does not exist + let tranche_currency_id = CurrencyId::Tranche(pool_id, tranche_id); - assert_noop!( - pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( - RawOrigin::Signed(POOL_ADMIN.into()).into(), - pool_id, - tranche_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::TrancheMetadataNotFound - ); - }); - } + orml_asset_registry::Metadata::::remove(tranche_currency_id); - #[test_runtimes([development])] - fn update_member() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + assert_noop!( + pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( + RawOrigin::Signed(POOL_ADMIN.into()).into(), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheMetadataNotFound ); + }); + } - setup_test(&mut env); - - env.parachain_state_mut(|| { - // Now create the pool - let pool_id = POOL_ID; - - create_ausd_pool::(pool_id); + #[test_runtimes([development])] + fn update_member() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - let tranche_id = default_tranche_id::(pool_id); + setup_test(&mut env); - // Finally, verify we can call pallet_liquidity_pools::Pallet::::add_tranche - // successfully when given a valid pool + tranche id pair. - let new_member = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [3; 20]); + env.parachain_state_mut(|| { + // Now create the pool + let pool_id = POOL_ID; - // Make ALICE the MembersListAdmin of this Pool - assert_ok!(pallet_permissions::Pallet::::add( - ::RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - Keyring::Alice.into(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); + create_ausd_pool::(pool_id); - // Verify it fails if the destination is not whitelisted yet - assert_noop!( - pallet_liquidity_pools::Pallet::::update_member( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - tranche_id, - new_member.clone(), - DEFAULT_VALIDITY, - ), - pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, - ); + let tranche_id = default_tranche_id::(pool_id); - // Whitelist destination as TrancheInvestor of this Pool - crate::generic::utils::pool::give_role::( - AccountConverter::convert(new_member.clone()), - pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), DEFAULT_VALIDITY), - ); + // Finally, verify we can call pallet_liquidity_pools::Pallet::::add_tranche + // successfully when given a valid pool + tranche id pair. + let new_member = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [3; 20]); - // Verify the Investor role was set as expected in Permissions - assert!(pallet_permissions::Pallet::::has( - PermissionScope::Pool(pool_id), - AccountConverter::convert(new_member.clone()), - Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, DEFAULT_VALIDITY)), - )); + // Make ALICE the MembersListAdmin of this Pool + assert_ok!(pallet_permissions::Pallet::::add( + ::RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + Keyring::Alice.into(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); - // Verify it now works - assert_ok!(pallet_liquidity_pools::Pallet::::update_member( + // Verify it fails if the destination is not whitelisted yet + assert_noop!( + pallet_liquidity_pools::Pallet::::update_member( RawOrigin::Signed(Keyring::Alice.into()).into(), pool_id, tranche_id, - new_member, + new_member.clone(), DEFAULT_VALIDITY, - )); - - // Verify it cannot be called for another member without whitelisting the domain - // beforehand - assert_noop!( - pallet_liquidity_pools::Pallet::::update_member( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - tranche_id, - DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [9; 20]), - DEFAULT_VALIDITY, - ), - pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, - ); - }); - } - - #[test_runtimes([development])] - fn update_token_price() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + ), + pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, ); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let currency_id = AUSD_CURRENCY_ID; - let pool_id = POOL_ID; + // Whitelist destination as TrancheInvestor of this Pool + crate::generic::utils::pool::give_role::( + AccountConverter::convert(new_member.clone()), + pool_id, + PoolRole::TrancheInvestor(default_tranche_id::(pool_id), DEFAULT_VALIDITY), + ); - enable_liquidity_pool_transferability::(currency_id); + // Verify the Investor role was set as expected in Permissions + assert!(pallet_permissions::Pallet::::has( + PermissionScope::Pool(pool_id), + AccountConverter::convert(new_member.clone()), + Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, DEFAULT_VALIDITY)), + )); - create_ausd_pool::(pool_id); + // Verify it now works + assert_ok!(pallet_liquidity_pools::Pallet::::update_member( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + tranche_id, + new_member, + DEFAULT_VALIDITY, + )); - assert_ok!(pallet_liquidity_pools::Pallet::::update_token_price( - RawOrigin::Signed(Keyring::Bob.into()).into(), + // Verify it cannot be called for another member without whitelisting the domain + // beforehand + assert_noop!( + pallet_liquidity_pools::Pallet::::update_member( + RawOrigin::Signed(Keyring::Alice.into()).into(), pool_id, - default_tranche_id::(pool_id), - currency_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - )); - }); - } - - #[test_runtimes([development])] - fn add_currency() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + tranche_id, + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [9; 20]), + DEFAULT_VALIDITY, + ), + pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, ); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn update_token_price() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - let gateway_sender = ::Sender::get(); + setup_test(&mut env); - let currency_id = AUSD_CURRENCY_ID; + env.parachain_state_mut(|| { + let currency_id = AUSD_CURRENCY_ID; + let pool_id = POOL_ID; - enable_liquidity_pool_transferability::(currency_id); + enable_liquidity_pool_transferability::(currency_id); - assert_eq!( - orml_tokens::Pallet::::free_balance(GLMR_CURRENCY_ID, &gateway_sender), - DEFAULT_BALANCE_GLMR - ); + create_ausd_pool::(pool_id); - assert_ok!(pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - currency_id, - )); - - let currency_index = - pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) - .expect("can get general index for currency"); - - let LiquidityPoolsWrappedToken::EVM { - address: evm_address, - .. - } = pallet_liquidity_pools::Pallet::::try_get_wrapped_token(¤cy_id) - .expect("can get wrapped token"); - - let outbound_message = - pallet_liquidity_pools_gateway::OutboundMessageQueue::::get( - T::OutboundMessageNonce::one(), - ) - .expect("expected outbound queue message"); + assert_ok!(pallet_liquidity_pools::Pallet::::update_token_price( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + default_tranche_id::(pool_id), + currency_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + )); + }); + } - assert_eq!( - outbound_message.2, - Message::AddCurrency { - currency: currency_index, - evm_address, - }, - ); - }); - } + #[test_runtimes([development])] + fn add_currency() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - #[test_runtimes([development])] - fn add_currency_should_fail() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), - ); + setup_test(&mut env); - setup_test(&mut env); + env.parachain_state_mut(|| { + let gateway_sender = ::Sender::get(); - env.parachain_state_mut(|| { - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - CurrencyId::ForeignAsset(42) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - CurrencyId::Native - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); + let currency_id = AUSD_CURRENCY_ID; - // Should fail to add currency_id which is missing a registered - // Location - let currency_id = CurrencyId::ForeignAsset(100); - - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - AssetMetadata { - name: BoundedVec::default(), - symbol: BoundedVec::default(), - decimals: 12, - location: None, - existential_deposit: 1_000_000, - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - mintable: false, - permissioned: false, - pool_currency: false, - local_representation: None, - }, - }, - Some(currency_id) - )); + enable_liquidity_pool_transferability::(currency_id); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - currency_id - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); + assert_eq!( + orml_tokens::Pallet::::free_balance(GLMR_CURRENCY_ID, &gateway_sender), + DEFAULT_BALANCE_GLMR + ); - // Add convertable Location to metadata but remove transferability - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add multilocation to metadata for some random EVM chain id for - // which no instance is registered - Some(Some(liquidity_pools_transferable_multilocation::( - u64::MAX, - [1u8; 20], - ))), - Some(CustomMetadata { - // Changed: Disallow liquidityPools transferability - transferability: CrossChainTransferability::Xcm(Default::default()), - ..Default::default() - }), - )); + assert_ok!(pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + currency_id, + )); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - currency_id - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); + let currency_index = + pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) + .expect("can get general index for currency"); - // Switch transferability from XCM to None - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Changed: Disallow cross chain transferability entirely - transferability: CrossChainTransferability::None, - ..Default::default() - }) - )); + let LiquidityPoolsWrappedToken::EVM { + address: evm_address, + .. + } = pallet_liquidity_pools::Pallet::::try_get_wrapped_token(¤cy_id) + .expect("can get wrapped token"); - assert_noop!( - pallet_liquidity_pools::Pallet::::add_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - currency_id - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - }); - } + let outbound_message = pallet_liquidity_pools_gateway::OutboundMessageQueue::::get( + T::OutboundMessageNonce::one(), + ) + .expect("expected outbound queue message"); - #[test_runtimes([development])] - fn allow_investment_currency() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + assert_eq!( + outbound_message.2, + Message::AddCurrency { + currency: currency_index, + evm_address, + }, ); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn add_currency_should_fail() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - let currency_id = AUSD_CURRENCY_ID; - let pool_id = POOL_ID; - let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; - let evm_address = [1u8; 20]; + setup_test(&mut env); - // Create an AUSD pool - create_ausd_pool::(pool_id); + env.parachain_state_mut(|| { + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + CurrencyId::ForeignAsset(42) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + CurrencyId::Native + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); - enable_liquidity_pool_transferability::(currency_id); + // Should fail to add currency_id which is missing a registered + // Location + let currency_id = CurrencyId::ForeignAsset(100); - // Enable LiquidityPools transferability - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add location which can be converted to LiquidityPoolsWrappedToken - Some(Some(liquidity_pools_transferable_multilocation::( - evm_chain_id, - evm_address, - ))), - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + AssetMetadata { + name: BoundedVec::default(), + symbol: BoundedVec::default(), + decimals: 12, + location: None, + existential_deposit: 1_000_000, + additional: CustomMetadata { transferability: CrossChainTransferability::LiquidityPools, - pool_currency: true, - ..Default::default() - }) - )); + mintable: false, + permissioned: false, + pool_currency: false, + local_representation: None, + }, + }, + Some(currency_id) + )); - assert_ok!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ) - ); + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + currency_id + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); - assert_noop!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Charlie.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); - }); - } + // Add convertable Location to metadata but remove transferability + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add multilocation to metadata for some random EVM chain id for + // which no instance is registered + Some(Some(liquidity_pools_transferable_multilocation::( + u64::MAX, + [1u8; 20], + ))), + Some(CustomMetadata { + // Changed: Disallow liquidityPools transferability + transferability: CrossChainTransferability::Xcm(Default::default()), + ..Default::default() + }), + )); - #[test_runtimes([development])] - fn allow_investment_currency_should_fail() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + currency_id + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - setup_test(&mut env); + // Switch transferability from XCM to None + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Changed: Disallow cross chain transferability entirely + transferability: CrossChainTransferability::None, + ..Default::default() + }) + )); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let currency_id = CurrencyId::ForeignAsset(42); - let ausd_currency_id = AUSD_CURRENCY_ID; + assert_noop!( + pallet_liquidity_pools::Pallet::::add_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + currency_id + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + }); + } - // Should fail if pool does not exist - assert_noop!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); + #[test_runtimes([development])] + fn allow_investment_currency() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - // Register currency_id with pool_currency set to true - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - AssetMetadata { - name: BoundedVec::default(), - symbol: BoundedVec::default(), - decimals: 12, - location: None, - existential_deposit: 1_000_000, - additional: CustomMetadata { - pool_currency: true, - ..Default::default() - }, - }, - Some(currency_id) - )); + setup_test(&mut env); - // Create pool - create_currency_pool::(pool_id, currency_id, 10_000 * decimals(12)); + env.parachain_state_mut(|| { + let currency_id = AUSD_CURRENCY_ID; + let pool_id = POOL_ID; + let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; + let evm_address = [1u8; 20]; - enable_liquidity_pool_transferability::(ausd_currency_id); + // Create an AUSD pool + create_ausd_pool::(pool_id); - // Should fail if currency is not liquidityPools transferable - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Disallow any cross chain transferability - transferability: CrossChainTransferability::None, - // Changed: Allow to be usable as pool currency - pool_currency: true, - ..Default::default() - }), - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); + enable_liquidity_pool_transferability::(currency_id); - // Should fail if currency does not have any Location in metadata - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Changed: Allow liquidityPools transferability - transferability: CrossChainTransferability::LiquidityPools, - // Still allow to be pool currency - pool_currency: true, - ..Default::default() - }), - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); + // Enable LiquidityPools transferability + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add location which can be converted to LiquidityPoolsWrappedToken + Some(Some(liquidity_pools_transferable_multilocation::( + evm_chain_id, + evm_address, + ))), + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + pool_currency: true, + ..Default::default() + }) + )); - // Should fail if currency does not have LiquidityPoolsWrappedToken location in - // metadata - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), + assert_ok!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, currency_id, - None, - None, - None, - None, - // Changed: Add some location which cannot be converted to - // LiquidityPoolsWrappedToken - Some(Some(VersionedLocation::V4(Default::default()))), - // No change for transferability required as it is already allowed for - // LiquidityPools - None, - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::allow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); - }); - } - - #[test_runtimes([development])] - fn disallow_investment_currency() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + ) ); - setup_test(&mut env); + assert_noop!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Charlie.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); + }); + } - env.parachain_state_mut(|| { - let currency_id = AUSD_CURRENCY_ID; - let pool_id = POOL_ID; - let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; - let evm_address = [1u8; 20]; + #[test_runtimes([development])] + fn allow_investment_currency_should_fail() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - // Create an AUSD pool - create_ausd_pool::(pool_id); + setup_test(&mut env); - enable_liquidity_pool_transferability::(currency_id); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let currency_id = CurrencyId::ForeignAsset(42); + let ausd_currency_id = AUSD_CURRENCY_ID; - // Enable LiquidityPools transferability - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add location which can be converted to LiquidityPoolsWrappedToken - Some(Some(liquidity_pools_transferable_multilocation::( - evm_chain_id, - evm_address, - ))), - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - pool_currency: true, - ..Default::default() - }) - )); - - assert_ok!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ) - ); - - assert_noop!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Charlie.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); - }); - } - - #[test_runtimes([development])] - fn disallow_investment_currency_should_fail() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + // Should fail if pool does not exist + assert_noop!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::NotPoolAdmin ); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let currency_id = CurrencyId::ForeignAsset(42); - let ausd_currency_id = AUSD_CURRENCY_ID; - - // Should fail if pool does not exist - assert_noop!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); - - // Register currency_id with pool_currency set to true - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - AssetMetadata { - name: BoundedVec::default(), - symbol: BoundedVec::default(), - decimals: 12, - location: None, - existential_deposit: 1_000_000, - additional: CustomMetadata { - pool_currency: true, - ..Default::default() - }, + // Register currency_id with pool_currency set to true + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + AssetMetadata { + name: BoundedVec::default(), + symbol: BoundedVec::default(), + decimals: 12, + location: None, + existential_deposit: 1_000_000, + additional: CustomMetadata { + pool_currency: true, + ..Default::default() }, - Some(currency_id) - )); + }, + Some(currency_id) + )); - // Create pool - create_currency_pool::(pool_id, currency_id, 10_000 * decimals(12)); + // Create pool + create_currency_pool::(pool_id, currency_id, 10_000 * decimals(12)); - enable_liquidity_pool_transferability::(ausd_currency_id); + enable_liquidity_pool_transferability::(ausd_currency_id); - // Should fail if currency is not liquidityPools transferable - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), + // Should fail if currency is not liquidityPools transferable + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Disallow any cross chain transferability + transferability: CrossChainTransferability::None, + // Changed: Allow to be usable as pool currency + pool_currency: true, + ..Default::default() + }), + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Disallow any cross chain transferability - transferability: CrossChainTransferability::None, - // Changed: Allow to be usable as pool currency - pool_currency: true, - ..Default::default() - }), - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); - // Should fail if currency does not have any Location in metadata - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), + // Should fail if currency does not have any Location in metadata + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Changed: Allow liquidityPools transferability + transferability: CrossChainTransferability::LiquidityPools, + // Still allow to be pool currency + pool_currency: true, + ..Default::default() + }), + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Changed: Allow liquidityPools transferability - transferability: CrossChainTransferability::LiquidityPools, - // Still allow to be pool currency - pool_currency: true, - ..Default::default() - }), - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); - // Should fail if currency does not have LiquidityPoolsWrappedToken location in - // metadata - assert_ok!(orml_asset_registry::Pallet::::update_asset( - ::RuntimeOrigin::root(), + // Should fail if currency does not have LiquidityPoolsWrappedToken location in + // metadata + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add some location which cannot be converted to + // LiquidityPoolsWrappedToken + Some(Some(VersionedLocation::V4(Default::default()))), + // No change for transferability required as it is already allowed for + // LiquidityPools + None, + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::allow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, currency_id, - None, - None, - None, - None, - // Changed: Add some location which cannot be converted to - // LiquidityPoolsWrappedToken - Some(Some(VersionedLocation::V4(Default::default()))), - // No change for transferability required as it is already allowed for - // LiquidityPools - None, - )); - assert_noop!( - pallet_liquidity_pools::Pallet::::disallow_investment_currency( - RawOrigin::Signed(Keyring::Bob.into()).into(), - pool_id, - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); - }); - } - - #[test_runtimes([development])] - fn schedule_upgrade() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken ); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn disallow_investment_currency() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - // Only Root can call `schedule_upgrade` - assert_noop!( - pallet_liquidity_pools::Pallet::::schedule_upgrade( - RawOrigin::Signed(Keyring::Bob.into()).into(), - MOONBEAM_EVM_CHAIN_ID, - [7; 20] - ), - BadOrigin - ); + setup_test(&mut env); - // Now it finally works - assert_ok!(pallet_liquidity_pools::Pallet::::schedule_upgrade( - ::RuntimeOrigin::root(), - MOONBEAM_EVM_CHAIN_ID, - [7; 20] - )); - }); - } + env.parachain_state_mut(|| { + let currency_id = AUSD_CURRENCY_ID; + let pool_id = POOL_ID; + let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; + let evm_address = [1u8; 20]; - #[test_runtimes([development])] - fn cancel_upgrade() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), - ); + // Create an AUSD pool + create_ausd_pool::(pool_id); - setup_test(&mut env); + enable_liquidity_pool_transferability::(currency_id); - env.parachain_state_mut(|| { - // Only Root can call `cancel_upgrade` - assert_noop!( - pallet_liquidity_pools::Pallet::::cancel_upgrade( - RawOrigin::Signed(Keyring::Bob.into()).into(), - MOONBEAM_EVM_CHAIN_ID, - [7; 20] - ), - BadOrigin - ); + // Enable LiquidityPools transferability + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add location which can be converted to LiquidityPoolsWrappedToken + Some(Some(liquidity_pools_transferable_multilocation::( + evm_chain_id, + evm_address, + ))), + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + pool_currency: true, + ..Default::default() + }) + )); - // Now it finally works - assert_ok!(pallet_liquidity_pools::Pallet::::cancel_upgrade( - ::RuntimeOrigin::root(), - MOONBEAM_EVM_CHAIN_ID, - [7; 20] - )); - }); - } + assert_ok!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ) + ); - #[test_runtimes([development])] - fn update_tranche_token_metadata() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), + assert_noop!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Charlie.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::NotPoolAdmin ); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn disallow_investment_currency_should_fail() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - // NOTE: Default pool admin is BOB - create_ausd_pool::(pool_id); + setup_test(&mut env); - // Missing tranche token should throw - let nonexistent_tranche = [71u8; 16]; + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let currency_id = CurrencyId::ForeignAsset(42); + let ausd_currency_id = AUSD_CURRENCY_ID; - assert_noop!( - pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - nonexistent_tranche, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::TrancheNotFound - ); + // Should fail if pool does not exist + assert_noop!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); - let tranche_id = default_tranche_id::(pool_id); + // Register currency_id with pool_currency set to true + assert_ok!(orml_asset_registry::Pallet::::register_asset( + ::RuntimeOrigin::root(), + AssetMetadata { + name: BoundedVec::default(), + symbol: BoundedVec::default(), + decimals: 12, + location: None, + existential_deposit: 1_000_000, + additional: CustomMetadata { + pool_currency: true, + ..Default::default() + }, + }, + Some(currency_id) + )); - // Moving the update to another domain can be called by anyone - assert_ok!( - pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - tranche_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ) - ); + // Create pool + create_currency_pool::(pool_id, currency_id, 10_000 * decimals(12)); - // Edge case: Should throw if tranche exists but metadata does not exist - let tranche_currency_id = CurrencyId::Tranche(pool_id, tranche_id); + enable_liquidity_pool_transferability::(ausd_currency_id); - orml_asset_registry::Metadata::::remove(tranche_currency_id); + // Should fail if currency is not liquidityPools transferable + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Disallow any cross chain transferability + transferability: CrossChainTransferability::None, + // Changed: Allow to be usable as pool currency + pool_currency: true, + ..Default::default() + }), + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); - assert_noop!( - pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( - RawOrigin::Signed(POOL_ADMIN.into()).into(), - pool_id, - tranche_id, - Domain::EVM(MOONBEAM_EVM_CHAIN_ID), - ), - pallet_liquidity_pools::Error::::TrancheMetadataNotFound - ); - }); - } + // Should fail if currency does not have any Location in metadata + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Changed: Allow liquidityPools transferability + transferability: CrossChainTransferability::LiquidityPools, + // Still allow to be pool currency + pool_currency: true, + ..Default::default() + }), + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); + + // Should fail if currency does not have LiquidityPoolsWrappedToken location in + // metadata + assert_ok!(orml_asset_registry::Pallet::::update_asset( + ::RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add some location which cannot be converted to + // LiquidityPoolsWrappedToken + Some(Some(VersionedLocation::V4(Default::default()))), + // No change for transferability required as it is already allowed for + // LiquidityPools + None, + )); + assert_noop!( + pallet_liquidity_pools::Pallet::::disallow_investment_currency( + RawOrigin::Signed(Keyring::Bob.into()).into(), + pool_id, + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); + }); } - mod foreign_investments { - use super::*; + #[test_runtimes([development])] + fn schedule_upgrade() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - mod same_currencies { - use super::*; + setup_test(&mut env); - #[test_runtimes([development])] - fn increase_invest_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![( - GLMR_CURRENCY_ID, - DEFAULT_BALANCE_GLMR, - )])) - .storage(), - ); + env.parachain_state_mut(|| { + // Only Root can call `schedule_upgrade` + assert_noop!( + pallet_liquidity_pools::Pallet::::schedule_upgrade( + RawOrigin::Signed(Keyring::Bob.into()).into(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + ), + BadOrigin + ); - setup_test(&mut env); + // Now it finally works + assert_ok!(pallet_liquidity_pools::Pallet::::schedule_upgrade( + ::RuntimeOrigin::root(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + )); + }); + } - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment::( - pool_id, - amount, - investor.clone(), - currency_id, - ); + #[test_runtimes([development])] + fn cancel_upgrade() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - // Verify the order was updated to the amount - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id::(), - ) - .amount, - amount - ); + setup_test(&mut env); - // Increasing again should just bump invest_amount - let msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - }); - } + env.parachain_state_mut(|| { + // Only Root can call `cancel_upgrade` + assert_noop!( + pallet_liquidity_pools::Pallet::::cancel_upgrade( + RawOrigin::Signed(Keyring::Bob.into()).into(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + ), + BadOrigin + ); - #[test_runtimes([development])] - fn decrease_invest_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Now it finally works + assert_ok!(pallet_liquidity_pools::Pallet::::cancel_upgrade( + ::RuntimeOrigin::root(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + )); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn update_tranche_token_metadata() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let invest_amount: u128 = 10 * decimals(12); - let decrease_amount = invest_amount / 3; - let final_amount = invest_amount - decrease_amount; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment::( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); + setup_test(&mut env); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: decrease_amount, - }; + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + // NOTE: Default pool admin is BOB + create_ausd_pool::(pool_id); - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - enable_liquidity_pool_transferability::(currency_id); + // Missing tranche token should throw + let nonexistent_tranche = [71u8; 16]; - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + assert_noop!( + pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + nonexistent_tranche, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheNotFound + ); - // Verify investment was decreased into investment account - assert_eq!( - orml_tokens::Pallet::::balance( - currency_id, - &default_investment_account::() - ), - final_amount - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: decrease_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id::(), - ) - .amount, - final_amount - ); - }); - } + let tranche_id = default_tranche_id::(pool_id); - #[test_runtimes([development])] - fn cancel_invest_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Moving the update to another domain can be called by anyone + assert_ok!( + pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ) + ); - setup_test(&mut env); + // Edge case: Should throw if tranche exists but metadata does not exist + let tranche_currency_id = CurrencyId::Tranche(pool_id, tranche_id); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let invest_amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment::( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); + orml_asset_registry::Metadata::::remove(tranche_currency_id); - // Verify investment account holds funds before cancelling - assert_eq!( - orml_tokens::Pallet::::balance( - currency_id, - &default_investment_account::() - ), - invest_amount - ); + assert_noop!( + pallet_liquidity_pools::Pallet::::update_tranche_token_metadata( + RawOrigin::Signed(POOL_ADMIN.into()).into(), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheMetadataNotFound + ); + }); + } +} - // Mock incoming cancel message - let msg = LiquidityPoolMessage::CancelInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - }; +mod foreign_investments { + use super::*; - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); + mod same_currencies { + use super::*; - enable_liquidity_pool_transferability::(currency_id); + #[test_runtimes([development])] + fn increase_invest_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![( + GLMR_CURRENCY_ID, + DEFAULT_BALANCE_GLMR, + )])) + .storage(), + ); - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + setup_test(&mut env); - // Verify investment was entirely drained from investment account - assert_eq!( - orml_tokens::Pallet::::balance( - currency_id, - &default_investment_account::() - ), - 0 - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: invest_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id::(), - ) - .amount, - 0 - ); - }); - } + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - #[test_runtimes([development])] - fn collect_invest_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - setup_test(&mut env); + // Set permissions and execute initial investment + do_initial_increase_investment::(pool_id, amount, investor.clone(), currency_id); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - enable_liquidity_pool_transferability::(currency_id); - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - let investment_currency_id: CurrencyId = default_investment_id::().into(); - // Set permissions and execute initial investment - do_initial_increase_investment::( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = frame_system::Pallet::::events(); + // Verify the order was updated to the amount + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id::(), + ) + .amount, + amount + ); - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(pallet_investments::Pallet::::process_invest_orders( - default_investment_id::() - )); + // Increasing again should just bump invest_amount + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); + }); + } - // Tranche tokens will be minted upon fulfillment - assert_eq!( - orml_tokens::Pallet::::total_issuance(investment_currency_id), - 0 - ); - assert_ok!(pallet_investments::Pallet::::invest_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::one(), - } - )); - assert_eq!( - orml_tokens::Pallet::::total_issuance(investment_currency_id), - amount - ); + #[test_runtimes([development])] + fn decrease_invest_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + setup_test(&mut env); - // Remove events before collect execution - let events_since_collect: Vec<_> = frame_system::Pallet::::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let invest_amount: u128 = 10 * decimals(12); + let decrease_amount = invest_amount / 3; + let final_amount = invest_amount - decrease_amount; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Verify investment was transferred to the domain locator - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &sending_domain_locator - ), - amount - ); + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id::(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: default_investment_id::(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - let sender = ::Sender::get(); - - // Clearing of foreign InvestState should be dispatched - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - currency_payout: amount, - tranche_tokens_payout: amount, - remaining_invest_amount: 0, - }, - } - .into() - })); - }); - } - - #[test_runtimes([development])] - fn partially_collect_investment_for_through_investments() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + // Set permissions and execute initial investment + do_initial_increase_investment::( + pool_id, + invest_amount, + investor.clone(), + currency_id, ); - setup_test(&mut env); + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: decrease_amount, + }; - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let invest_amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment::( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability::(currency_id); - let investment_currency_id: CurrencyId = default_investment_id::().into(); + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + enable_liquidity_pool_transferability::(currency_id); - assert!( - !pallet_investments::Pallet::::investment_requires_collect( - &investor, - default_investment_id::() - ) - ); + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche - // tokens - assert_ok!(pallet_investments::Pallet::::process_invest_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + // Verify investment was decreased into investment account + assert_eq!( + orml_tokens::Pallet::::balance( + currency_id, + &default_investment_account::() + ), + final_amount + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::from_percent(50), - price: Ratio::checked_from_rational(1, 4).unwrap(), - } - )); + ) + .amount, + final_amount + ); + }); + } - // Pre collect assertions - assert!( - pallet_investments::Pallet::::investment_requires_collect( - &investor, - default_investment_id::() - ) - ); + #[test_runtimes([development])] + fn cancel_invest_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - // Collecting through Investments should denote amounts and transition - // state - assert_ok!(pallet_investments::Pallet::::collect_investments_for( - RawOrigin::Signed(Keyring::Alice.into()).into(), - investor.clone(), - default_investment_id::() - )); - assert!( - !pallet_investments::Pallet::::investment_requires_collect( - &investor, - default_investment_id::() - ) - ); + setup_test(&mut env); - // Tranche Tokens should still be transferred to collected to - // domain locator account already - assert_eq!( - orml_tokens::Pallet::::balance(investment_currency_id, &investor), - 0 - ); - assert_eq!( - orml_tokens::Pallet::::balance( - investment_currency_id, - &sending_domain_locator - ), - invest_amount * 2 - ); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: invest_amount * 2, - remaining_investment_invest: invest_amount / 2, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - let sender = ::Sender::get(); - - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: pallet_liquidity_pools::Message::ExecutedCollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - currency_payout: invest_amount / 2, - tranche_tokens_payout: invest_amount * 2, - remaining_invest_amount: invest_amount / 2, - }, - } - .into() - })); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let invest_amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Process rest of investment at 50% rate (1 pool currency = 2 tranche tokens) - assert_ok!(pallet_investments::Pallet::::process_invest_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::invest_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::checked_from_rational(1, 2).unwrap(), - } - )); - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id::(), - ) - .amount, - 0 - ); - assert_eq!( - orml_tokens::Pallet::::total_issuance(investment_currency_id), - invest_amount * 3 - ); + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - // Collect remainder through Investments - assert_ok!(pallet_investments::Pallet::::collect_investments_for( - RawOrigin::Signed(Keyring::Alice.into()).into(), - investor.clone(), - default_investment_id::() - )); - assert!( - !pallet_investments::Pallet::::investment_requires_collect( - &investor, - default_investment_id::() - ) - ); + // Set permissions and execute initial investment + do_initial_increase_investment::( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); - // Tranche Tokens should be transferred to collected to - // domain locator account already - let amount_tranche_tokens = invest_amount * 3; - assert_eq!( - orml_tokens::Pallet::::total_issuance(investment_currency_id), - amount_tranche_tokens - ); - assert!( - orml_tokens::Pallet::::balance(investment_currency_id, &investor) - .is_zero() - ); - assert_eq!( - orml_tokens::Pallet::::balance( - investment_currency_id, - &sending_domain_locator - ), - amount_tranche_tokens - ); - assert!(!frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: default_investment_id::(), - who: investor.clone(), - } - .into() - })); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![1], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: invest_amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - currency_payout: invest_amount / 2, - tranche_tokens_payout: invest_amount, - remaining_invest_amount: 0, - }, - } - .into() - })); + // Verify investment account holds funds before cancelling + assert_eq!( + orml_tokens::Pallet::::balance( + currency_id, + &default_investment_account::() + ), + invest_amount + ); - // Should fail to collect if `InvestmentState` does not - // exist - let msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - ), - pallet_foreign_investments::Error::::InfoNotFound - ); - }); - } + // Mock incoming cancel message + let msg = LiquidityPoolMessage::CancelInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + }; - #[test_runtimes([development])] - fn increase_redeem_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - setup_test(&mut env); + enable_liquidity_pool_transferability::(currency_id); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption::( - pool_id, - amount, - investor.clone(), + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); + + // Verify investment was entirely drained from investment account + assert_eq!( + orml_tokens::Pallet::::balance( currency_id, - ); + &default_investment_account::() + ), + 0 + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: invest_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id::(), + ) + .amount, + 0 + ); + }); + } - // Verify amount was noted in the corresponding order - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id::(), - ) - .amount, - amount - ); + #[test_runtimes([development])] + fn collect_invest_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - // Increasing again should just bump redeeming amount - assert_ok!(orml_tokens::Pallet::::mint_into( - default_investment_id::().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount - )); - let msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - }); - } + setup_test(&mut env); - #[test_runtimes([development])] - fn decrease_redeem_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + enable_liquidity_pool_transferability::(currency_id); - setup_test(&mut env); + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + let investment_currency_id: CurrencyId = default_investment_id::().into(); + // Set permissions and execute initial investment + do_initial_increase_investment::(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = frame_system::Pallet::::events(); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::InvestCollectedForNonClearedOrderId` be dispatched + assert_ok!(pallet_investments::Pallet::::process_invest_orders( + default_investment_id::() + )); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let redeem_amount = 10 * decimals(12); - let decrease_amount = redeem_amount / 3; - let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption::( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); + // Tranche tokens will be minted upon fulfillment + assert_eq!( + orml_tokens::Pallet::::total_issuance(investment_currency_id), + 0 + ); + assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::one(), + } + )); + assert_eq!( + orml_tokens::Pallet::::total_issuance(investment_currency_id), + amount + ); - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id::( - pool_id, - default_tranche_id::(pool_id) - )), - 0 - ); + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: decrease_amount, - }; + // Remove events before collect execution + let events_since_collect: Vec<_> = frame_system::Pallet::::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Verify investment was transferred to the domain locator + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &sending_domain_locator + ), + amount + ); - // Verify investment was decreased into investment account - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &default_investment_account::(), - ), - final_amount - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &investor - ), - 0 - ); - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &sending_domain_locator - ), - decrease_amount - ); + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id::(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id::(), + who: investor.clone(), + } + .into() + })); - // Order should have been updated - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { investment_id: default_investment_id::(), submitted_at: 0, who: investor.clone(), - amount: final_amount + amount: 0, } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id::(), - ) - .amount, - final_amount - ); - - let sender = ::Sender::get(); + .into() + })); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedDecreaseRedeemOrder { + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + let sender = ::Sender::get(); + + // Clearing of foreign InvestState should be dispatched + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedCollectInvest { pool_id, tranche_id: default_tranche_id::(pool_id), investor: investor.clone().into(), currency: general_currency_index::(currency_id), - tranche_tokens_payout: decrease_amount, - remaining_redeem_amount: final_amount, + currency_payout: amount, + tranche_tokens_payout: amount, + remaining_invest_amount: 0, }, } - .into() - })); - }); - } - - #[test_runtimes([development])] - fn cancel_redeem_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let redeem_amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption::( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id::( - pool_id, - default_tranche_id::(pool_id) - )), - 0 - ); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::CancelRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - }; - - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + .into() + })); + }); + } - // Verify investment was decreased into investment account - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &default_investment_account::(), - ), - 0 - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &investor - ), - 0 - ); - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &sending_domain_locator - ), - redeem_amount - ); + #[test_runtimes([development])] + fn partially_collect_investment_for_through_investments() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - // Order should have been updated - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id::(), - ) - .amount, - 0 - ); - }); - } + setup_test(&mut env); - #[test_runtimes([development])] - fn fully_collect_redeem_order() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let invest_amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment::( + pool_id, + invest_amount, + investor.clone(), + currency_id, ); + enable_liquidity_pool_transferability::(currency_id); + let investment_currency_id: CurrencyId = default_investment_id::().into(); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - - // Create new pool - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_redemption::( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = frame_system::Pallet::::events(); - - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(orml_tokens::Pallet::::mint_into( - currency_id, - &pool_account, - amount - )); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + assert!( + !pallet_investments::Pallet::::investment_requires_collect( + &investor, default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::one(), - } - )); - - // Enable liquidity pool transferability - enable_liquidity_pool_transferability::(currency_id); - - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - }; - - // Execute byte message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Remove events before collect execution - let events_since_collect: Vec<_> = frame_system::Pallet::::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); - - // Verify collected redemption was burned from investor - assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount - } - .into())); - - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id::(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: default_investment_id::(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id::(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![0], - who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: amount, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - let sender = ::Sender::get(); - - // Clearing of foreign RedeemState should be dispatched - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectRedeem { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - currency_payout: amount, - tranche_tokens_payout: amount, - remaining_redeem_amount: 0, - }, - } - .into() - })); - }); - } - - #[test_runtimes([development])] - fn partially_collect_redemption_for_through_investments() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + ) ); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let redeem_amount = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_redemption::( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability::(currency_id); - - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(orml_tokens::Pallet::::mint_into( - currency_id, - &pool_account, - redeem_amount - )); - assert!( - !pallet_investments::Pallet::::redemption_requires_collect( - &investor, - default_investment_id::() - ) - ); + // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(pallet_investments::Pallet::::process_invest_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::from_percent(50), + price: Ratio::checked_from_rational(1, 4).unwrap(), + } + )); - // Process 50% of redemption at 25% rate, i.e. 1 pool currency = 4 tranche - // tokens - assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + // Pre collect assertions + assert!( + pallet_investments::Pallet::::investment_requires_collect( + &investor, default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::from_percent(50), - price: Ratio::checked_from_rational(1, 4).unwrap(), - } - )); - - // Pre collect assertions - assert!( - pallet_investments::Pallet::::redemption_requires_collect( - &investor, - default_investment_id::() - ) - ); + ) + ); - // Collecting through investments should denote amounts and transition - // state - assert_ok!(pallet_investments::Pallet::::collect_redemptions_for( - RawOrigin::Signed(Keyring::Alice.into()).into(), - investor.clone(), + // Collecting through Investments should denote amounts and transition + // state + assert_ok!(pallet_investments::Pallet::::collect_investments_for( + RawOrigin::Signed(Keyring::Alice.into()).into(), + investor.clone(), + default_investment_id::() + )); + assert!( + !pallet_investments::Pallet::::investment_requires_collect( + &investor, default_investment_id::() - )); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![0], - who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: redeem_amount / 8, - remaining_investment_redeem: redeem_amount / 2, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); + ) + ); - let sender = ::Sender::get(); + // Tranche Tokens should still be transferred to collected to + // domain locator account already + assert_eq!( + orml_tokens::Pallet::::balance(investment_currency_id, &investor), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::balance( + investment_currency_id, + &sending_domain_locator + ), + invest_amount * 2 + ); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: invest_amount * 2, + remaining_investment_invest: invest_amount / 2, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + let sender = ::Sender::get(); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { sender: sender.clone(), domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectRedeem { + message: pallet_liquidity_pools::Message::ExecutedCollectInvest { pool_id, tranche_id: default_tranche_id::(pool_id), investor: investor.clone().into(), currency: general_currency_index::(currency_id), - currency_payout: redeem_amount / 8, - tranche_tokens_payout: redeem_amount / 2, - remaining_redeem_amount: redeem_amount / 2, + currency_payout: invest_amount / 2, + tranche_tokens_payout: invest_amount * 2, + remaining_invest_amount: invest_amount / 2, }, } - .into() - })); - assert!( - !pallet_investments::Pallet::::redemption_requires_collect( - &investor, - default_investment_id::() - ) - ); - // Since foreign currency is pool currency, the swap is immediately fulfilled - // and ExecutedCollectRedeem dispatched - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: redeem_amount / 8 - } - .into())); + .into() + })); - // Process rest of redemption at 50% rate - assert_ok!(pallet_investments::Pallet::::process_redeem_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( + // Process rest of investment at 50% rate (1 pool currency = 2 tranche tokens) + assert_ok!(pallet_investments::Pallet::::process_invest_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::checked_from_rational(1, 2).unwrap(), + } + )); + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::checked_from_rational(1, 2).unwrap(), - } - )); - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id::(), - ) - .amount, - 0 - ); + ) + .amount, + 0 + ); + assert_eq!( + orml_tokens::Pallet::::total_issuance(investment_currency_id), + invest_amount * 3 + ); - // Collect remainder through Investments - assert_ok!(pallet_investments::Pallet::::collect_redemptions_for( - RawOrigin::Signed(Keyring::Alice.into()).into(), - investor.clone(), + // Collect remainder through Investments + assert_ok!(pallet_investments::Pallet::::collect_investments_for( + RawOrigin::Signed(Keyring::Alice.into()).into(), + investor.clone(), + default_investment_id::() + )); + assert!( + !pallet_investments::Pallet::::investment_requires_collect( + &investor, default_investment_id::() - )); - assert!( - !pallet_investments::Pallet::::redemption_requires_collect( - &investor, - default_investment_id::() - ) - ); - assert!(!frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: default_investment_id::(), - who: investor.clone(), - } - .into() - })); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: default_investment_id::(), - processed_orders: vec![1], - who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: redeem_amount / 4, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - // Verify collected redemption was burned from investor - assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); - assert!(frame_system::Pallet::::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, + ) + ); + + // Tranche Tokens should be transferred to collected to + // domain locator account already + let amount_tranche_tokens = invest_amount * 3; + assert_eq!( + orml_tokens::Pallet::::total_issuance(investment_currency_id), + amount_tranche_tokens + ); + assert!( + orml_tokens::Pallet::::balance(investment_currency_id, &investor).is_zero() + ); + assert_eq!( + orml_tokens::Pallet::::balance( + investment_currency_id, + &sending_domain_locator + ), + amount_tranche_tokens + ); + assert!(!frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id::(), + who: investor.clone(), + } + .into() + })); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![1], who: investor.clone(), - amount: redeem_amount / 4 + collection: InvestCollection:: { + payout_investment_invest: invest_amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, } - .into())); - // Clearing of foreign RedeemState should have been dispatched exactly once - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + .into() + })); + + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { sender: sender.clone(), domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectRedeem { + message: LiquidityPoolMessage::ExecutedCollectInvest { pool_id, tranche_id: default_tranche_id::(pool_id), investor: investor.clone().into(), currency: general_currency_index::(currency_id), - currency_payout: redeem_amount / 4, - tranche_tokens_payout: redeem_amount / 2, - remaining_redeem_amount: 0, + currency_payout: invest_amount / 2, + tranche_tokens_payout: invest_amount, + remaining_invest_amount: 0, }, } - .into() - })); - }); - } - - mod should_fail { - use super::*; - - mod decrease_should_underflow { - use super::*; - - #[test_runtimes([development])] - fn invest_decrease_underflow() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + .into() + })); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let invest_amount: u128 = 10 * decimals(12); - let decrease_amount = invest_amount + 1; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool::( - pool_id, - currency_id, - currency_decimals.into(), - ); - do_initial_increase_investment::( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability::(currency_id); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - ), - pallet_foreign_investments::Error::::TooMuchDecrease - ); - }); - } + // Should fail to collect if `InvestmentState` does not + // exist + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + ), + pallet_foreign_investments::Error::::InfoNotFound + ); + }); + } - #[test_runtimes([development])] - fn redeem_decrease_underflow() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + #[test_runtimes([development])] + fn increase_redeem_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let redeem_amount: u128 = 10 * decimals(12); - let decrease_amount = redeem_amount + 1; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool::( - pool_id, - currency_id, - currency_decimals.into(), - ); - do_initial_increase_redemption::( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); + setup_test(&mut env); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - ), - DispatchError::Arithmetic(sp_runtime::ArithmeticError::Underflow) - ); - }); - } - } + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - mod should_throw_requires_collect { - use super::*; + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - #[test_runtimes([development])] - fn invest_requires_collect() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Set permissions and execute initial redemption + do_initial_increase_redemption::(pool_id, amount, investor.clone(), currency_id); - setup_test(&mut env); + // Verify amount was noted in the corresponding order + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id::(), + ) + .amount, + amount + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount: u128 = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool::( - pool_id, - currency_id, - currency_decimals.into(), - ); - do_initial_increase_investment::( - pool_id, - amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability::(currency_id); - - // Prepare collection - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(orml_tokens::Pallet::::mint_into( - currency_id, - &pool_account, - amount - )); - assert_ok!(pallet_investments::Pallet::::process_invest_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::invest_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::one(), - } - )); - - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: AUSD_ED, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - ), - pallet_investments::Error::::CollectRequired - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg - ), - pallet_investments::Error::::CollectRequired - ); - }); - } + // Increasing again should just bump redeeming amount + assert_ok!(orml_tokens::Pallet::::mint_into( + default_investment_id::().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount + )); + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); + }); + } - #[test_runtimes([development])] - fn redeem_requires_collect() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + #[test_runtimes([development])] + fn decrease_redeem_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - setup_test(&mut env); + setup_test(&mut env); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount: u128 = 10 * decimals(12); - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool::( - pool_id, - currency_id, - currency_decimals.into(), - ); - do_initial_increase_redemption::( - pool_id, - amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability::(currency_id); - - // Mint more into DomainLocator required for subsequent invest attempt - assert_ok!(orml_tokens::Pallet::::mint_into( - default_investment_id::().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - 1, - )); - - // Prepare collection - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(orml_tokens::Pallet::::mint_into( - currency_id, - &pool_account, - amount - )); - assert_ok!(pallet_investments::Pallet::::process_redeem_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::one(), - } - )); - - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - ), - pallet_investments::Error::::CollectRequired - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(currency_id), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg - ), - pallet_investments::Error::::CollectRequired - ); - }); - } - } + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let redeem_amount = 10 * decimals(12); + let decrease_amount = redeem_amount / 3; + let final_amount = redeem_amount - decrease_amount; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - mod payment_payout_currency { - use super::*; + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - #[test_runtimes([development])] - fn invalid_invest_payment_currency() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Set permissions and execute initial redemption + do_initial_increase_redemption::( + pool_id, + redeem_amount, + investor.clone(), + currency_id, + ); - setup_test(&mut env); + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id::( + pool_id, + default_tranche_id::(pool_id) + )), + 0 + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let amount = 6 * decimals(18); + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: decrease_amount, + }; - create_currency_pool::( - pool_id, - pool_currency, - currency_decimals.into(), - ); - do_initial_increase_investment::( - pool_id, - amount, - investor.clone(), - pool_currency, - ); + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - enable_usdt_trading::(pool_currency, amount, true, true, true); + // Verify investment was decreased into investment account + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &default_investment_account::(), + ), + final_amount + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &investor + ), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &sending_domain_locator + ), + decrease_amount + ); - // Should fail to increase, decrease or collect for - // another foreign currency as long as - // `InvestmentState` exists - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: AUSD_ED, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - let collect_msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - collect_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - }); + // Order should have been updated + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id::(), + ) + .amount, + final_amount + ); - #[test_runtimes([development])] - fn invalid_redeem_payout_currency() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let amount = 6 * decimals(18); + let sender = ::Sender::get(); - create_currency_pool::( - pool_id, - pool_currency, - currency_decimals.into(), - ); - do_initial_increase_redemption::( - pool_id, - amount, - investor.clone(), - pool_currency, - ); - enable_usdt_trading::(pool_currency, amount, true, true, true); - assert_ok!(orml_tokens::Pallet::::mint_into( - default_investment_id::().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount, - )); - - // Should fail to increase, decrease or collect for - // another foreign currency as long as - // `RedemptionState` exists - let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - let collect_msg = LiquidityPoolMessage::CollectRedeem { + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedDecreaseRedeemOrder { pool_id, tranche_id: default_tranche_id::(pool_id), investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - collect_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - }); - } - - #[test_runtimes([development])] - fn redeem_payout_currency_not_found() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + currency: general_currency_index::(currency_id), + tranche_tokens_payout: decrease_amount, + remaining_redeem_amount: final_amount, + }, + } + .into() + })); + }); + } - setup_test(&mut env); + #[test_runtimes([development])] + fn cancel_redeem_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let amount = 6 * decimals(18); + setup_test(&mut env); - create_currency_pool::( - pool_id, - pool_currency, - currency_decimals.into(), - ); - do_initial_increase_redemption::( - pool_id, - amount, - investor.clone(), - pool_currency, - ); - enable_usdt_trading::(pool_currency, amount, true, true, true); - assert_ok!(orml_tokens::Pallet::::mint_into( - default_investment_id::().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount, - )); - - // Should fail to decrease or collect for another - // foreign currency as long as `RedemptionState` - // exists - let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: 1, - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - - let collect_msg = LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - }; - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - collect_msg - ), - pallet_foreign_investments::Error::::MismatchedForeignCurrency - ); - }); - } - } - } - } + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let redeem_amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - mod mismatching_currencies { - use super::*; + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - #[test_runtimes([development])] - fn collect_foreign_investment_for() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + // Set permissions and execute initial redemption + do_initial_increase_redemption::( + pool_id, + redeem_amount, + investor.clone(), + currency_id, ); - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let pool_currency_decimals = currency_decimals::AUSD; - let invest_amount_pool_denominated: u128 = 6 * decimals(18); - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - let trader: AccountId = Keyring::Alice.into(); - create_currency_pool::( + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id::( pool_id, - pool_currency, - pool_currency_decimals.into(), - ); - - // USDT investment preparations - let invest_amount_foreign_denominated = enable_usdt_trading::( - pool_currency, - invest_amount_pool_denominated, - true, - true, - // not needed because we don't initialize a swap from pool to foreign here - false, - ); + default_tranche_id::(pool_id) + )), + 0 + ); - // Do first investment and fulfill swap order - do_initial_increase_investment::( - pool_id, - invest_amount_foreign_denominated, - investor.clone(), - foreign_currency, - ); - fulfill_swap_into_pool::( - pool_id, - default_order_id::(&investor), - invest_amount_pool_denominated, - invest_amount_foreign_denominated, - trader, - ); + // Mock incoming decrease message + let msg = LiquidityPoolMessage::CancelRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + }; - // Increase invest order to initialize ForeignInvestmentInfo - let msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Process 100% of investment at 50% rate (1 pool currency = 2 tranche tokens) - assert_ok!(pallet_investments::Pallet::::process_invest_orders( - default_investment_id::() - )); - assert_ok!(pallet_investments::Pallet::::invest_fulfillment( - default_investment_id::(), - FulfillmentWithPrice { - of_amount: Perquintill::one(), - price: Ratio::checked_from_rational(1, 2).unwrap(), - } - )); - assert_ok!(pallet_investments::Pallet::::collect_investments_for( - RawOrigin::Signed(Keyring::Alice.into()).into(), - investor.clone(), - default_investment_id::() - )); - assert!(orml_tokens::Pallet::::balance( + // Verify investment was decreased into investment account + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &default_investment_account::(), + ), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + orml_tokens::Pallet::::balance( default_investment_id::().into(), &investor - ) - .is_zero()); - assert_eq!( - orml_tokens::Pallet::::balance( - default_investment_id::().into(), - &sending_domain_locator - ), - invest_amount_pool_denominated * 2 - ); - - let sender = ::Sender::get(); - - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedCollectInvest { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - currency_payout: invest_amount_foreign_denominated, - tranche_tokens_payout: 2 * invest_amount_pool_denominated, - remaining_invest_amount: invest_amount_foreign_denominated, - }, - } - .into() - })); - }); - } - - /// Invest in pool currency, then increase in allowed foreign - /// currency, then decrease in same foreign currency multiple times. - #[test_runtimes([development])] - fn increase_fulfill_increase_decrease_decrease_partial() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), + ), + 0 + ); + assert_eq!( + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &sending_domain_locator + ), + redeem_amount ); - setup_test(&mut env); + // Order should have been updated + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id::(), + ) + .amount, + 0 + ); + }); + } - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let pool_currency_decimals = currency_decimals::AUSD; - let invest_amount_pool_denominated: u128 = 6 * decimals(18); - let trader: AccountId = Keyring::Alice.into(); - create_currency_pool::( - pool_id, - pool_currency, - pool_currency_decimals.into(), - ); + #[test_runtimes([development])] + fn fully_collect_redeem_order() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - // USDT investment preparations - let invest_amount_foreign_denominated = enable_usdt_trading::( - pool_currency, - invest_amount_pool_denominated, - true, - true, - true, - ); + setup_test(&mut env); - // Do first investment and fulfill swap order - do_initial_increase_investment::( - pool_id, - invest_amount_foreign_denominated, - investor.clone(), - foreign_currency, - ); - fulfill_swap_into_pool::( - pool_id, - default_order_id::(&investor), - invest_amount_pool_denominated, - invest_amount_foreign_denominated, - trader.clone(), - ); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); - // Do second investment and not fulfill swap order - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - )); + // Create new pool + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); - // Decrease pending pool swap by same amount - let decrease_msg_pool_swap_amount = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg_pool_swap_amount - )); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: ::Sender::get(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - currency_payout: invest_amount_foreign_denominated, - remaining_invest_amount: invest_amount_foreign_denominated, - }, - } - .into() - })); + // Set permissions and execute initial investment + do_initial_increase_redemption::(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = frame_system::Pallet::::events(); - // Decrease partially investing amount - let decrease_msg_partial_invest_amount = - LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated / 2, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg_partial_invest_amount.clone() - )); + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(orml_tokens::Pallet::::mint_into( + currency_id, + &pool_account, + amount + )); - // Consume entire investing amount by sending same message - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg_partial_invest_amount.clone() - )); - - // Swap decreased amount - assert_ok!(pallet_order_book::Pallet::::fill_order( - RawOrigin::Signed(trader.clone()).into(), - default_order_id::(&investor), - invest_amount_pool_denominated - )); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: ::Sender::get(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - currency_payout: invest_amount_foreign_denominated, - remaining_invest_amount: 0, - }, - } - .into() - })); - }); - } + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::RedeemCollectedForNonClearedOrderId` be dispatched + assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::one(), + } + )); - /// Propagate swaps only via OrderBook fulfillments. - /// - /// Flow: Increase, fulfill, decrease, fulfill - #[test_runtimes([development])] - fn invest_swaps_happy_path() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::tokens::(vec![ - (AUSD_CURRENCY_ID, AUSD_ED), - (USDT_CURRENCY_ID, USDT_ED), - ])) - .storage(), - ); + // Enable liquidity pool transferability + enable_liquidity_pool_transferability::(currency_id); - setup_test(&mut env); + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + }; - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let trader: AccountId = Keyring::Alice.into(); - let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let pool_currency_decimals = currency_decimals::AUSD; - let invest_amount_pool_denominated: u128 = 10 * decimals(18); - create_currency_pool::( - pool_id, - pool_currency, - pool_currency_decimals.into(), - ); - let invest_amount_foreign_denominated: u128 = enable_usdt_trading::( - pool_currency, - invest_amount_pool_denominated, - true, - true, - true, - ); + // Execute byte message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Increase such that active swap into USDT is initialized - do_initial_increase_investment::( - pool_id, - invest_amount_foreign_denominated, - investor.clone(), - foreign_currency, - ); + // Remove events before collect execution + let events_since_collect: Vec<_> = frame_system::Pallet::::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); - // Fulfilling order should propagate it from swapping to investing - let swap_order_id = default_order_id::(&investor); - fulfill_swap_into_pool::( - pool_id, - swap_order_id, - invest_amount_pool_denominated, - invest_amount_foreign_denominated, - trader.clone(), - ); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_order_book::Event::::OrderFulfillment { - order_id: swap_order_id, - placing_account: investor.clone(), - fulfilling_account: trader.clone(), - partial_fulfillment: false, - fulfillment_amount: invest_amount_foreign_denominated, - currency_in: pool_currency, - currency_out: foreign_currency, - ratio: Ratio::one(), - } - .into() - })); + // Verify collected redemption was burned from investor + assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount + } + .into())); - // Decrease by half the investment amount - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated / 2, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - )); - - let swap_order_id = default_order_id::(&investor); - assert_ok!(pallet_order_book::Pallet::::fill_order( - RawOrigin::Signed(trader.clone()).into(), - swap_order_id, - invest_amount_pool_denominated / 2 - )); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_order_book::Event::::OrderFulfillment { - order_id: swap_order_id, - placing_account: investor.clone(), - fulfilling_account: trader.clone(), - partial_fulfillment: false, - fulfillment_amount: invest_amount_pool_denominated / 2, - currency_in: foreign_currency, - currency_out: pool_currency, - ratio: Ratio::one(), - } - .into() - })); + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id::(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { + investment_id: default_investment_id::(), + who: investor.clone(), + } + .into() + })); - let sender = ::Sender::get(); + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id::(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: sender.clone(), - domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - currency_payout: invest_amount_foreign_denominated / 2, - remaining_invest_amount: invest_amount_foreign_denominated / 2, + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: amount, + remaining_investment_redeem: 0, }, + outcome: CollectOutcome::FullyCollected, } - .into() - })); - }); - } - - #[test_runtimes([development])] - fn increase_fulfill_decrease_fulfill_partial_increase() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); - let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let pool_currency_decimals = currency_decimals::AUSD; - let invest_amount_pool_denominated: u128 = 10 * decimals(18); - let trader: AccountId = Keyring::Alice.into(); - create_currency_pool::( - pool_id, - pool_currency, - pool_currency_decimals.into(), - ); - - // USDT investment preparations - let invest_amount_foreign_denominated = enable_usdt_trading::( - pool_currency, - invest_amount_pool_denominated, - true, - true, - true, - ); - - // Do first investment and fulfill swap order - do_initial_increase_investment::( - pool_id, - invest_amount_foreign_denominated, - investor.clone(), - foreign_currency, - ); - fulfill_swap_into_pool::( - pool_id, - default_order_id::(&investor), - invest_amount_pool_denominated, - invest_amount_foreign_denominated, - trader.clone(), - ); + .into() + })); - // Decrease pending pool swap by same amount - let decrease_msg_pool_swap_amount = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - decrease_msg_pool_swap_amount - )); - - // Fulfill decrease swap partially - assert_ok!(pallet_order_book::Pallet::::fill_order( - RawOrigin::Signed(trader.clone()).into(), - default_order_id::(&investor), - 3 * invest_amount_pool_denominated / 4 - )); - - // Increase more than pending swap (pool -> foreign) amount from decrease - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id::(pool_id), - investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - amount: invest_amount_foreign_denominated / 2, - }; - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - )); + let sender = ::Sender::get(); - assert!(frame_system::Pallet::::events().iter().any(|e| { - e.event - == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { - sender: ::Sender::get(), + // Clearing of foreign RedeemState should be dispatched + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), - message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { + message: LiquidityPoolMessage::ExecutedCollectRedeem { pool_id, tranche_id: default_tranche_id::(pool_id), investor: investor.clone().into(), - currency: general_currency_index::(foreign_currency), - currency_payout: invest_amount_foreign_denominated, - remaining_invest_amount: invest_amount_foreign_denominated / 2, + currency: general_currency_index::(currency_id), + currency_payout: amount, + tranche_tokens_payout: amount, + remaining_redeem_amount: 0, }, } - .into() - })); - }); - } + .into() + })); + }); } - } - - mod transfers { - use super::*; #[test_runtimes([development])] - fn transfer_non_tranche_tokens_from_local() { + fn partially_collect_redemption_for_through_investments() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) @@ -4035,103 +2709,700 @@ mod development { setup_test(&mut env); env.parachain_state_mut(|| { - let initial_balance = 2 * AUSD_ED; - let amount = initial_balance / 2; - let dest_address = DEFAULT_DOMAIN_ADDRESS_MOONBEAM; + let pool_id = POOL_ID; + let redeem_amount = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); let currency_id = AUSD_CURRENCY_ID; - let source_account = Keyring::Charlie; - - // Mint sufficient balance - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), - 0 + let currency_decimals = currency_decimals::AUSD; + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption::( + pool_id, + redeem_amount, + investor.clone(), + currency_id, ); + enable_liquidity_pool_transferability::(currency_id); + + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency assert_ok!(orml_tokens::Pallet::::mint_into( currency_id, - &source_account.into(), - initial_balance + &pool_account, + redeem_amount )); - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), - initial_balance + assert!( + !pallet_investments::Pallet::::redemption_requires_collect( + &investor, + default_investment_id::() + ) ); - // Only `ForeignAsset` can be transferred - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - CurrencyId::Tranche(42u64, [0u8; 16]), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::InvalidTransferCurrency - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - CurrencyId::Native, - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); + // Process 50% of redemption at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::from_percent(50), + price: Ratio::checked_from_rational(1, 4).unwrap(), + } + )); - // Cannot transfer as long as cross chain transferability is disabled - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - currency_id, - dest_address.clone(), - initial_balance, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + // Pre collect assertions + assert!( + pallet_investments::Pallet::::redemption_requires_collect( + &investor, + default_investment_id::() + ) ); - // Enable LiquidityPools transferability - enable_liquidity_pool_transferability::(currency_id); + // Collecting through investments should denote amounts and transition + // state + assert_ok!(pallet_investments::Pallet::::collect_redemptions_for( + RawOrigin::Signed(Keyring::Alice.into()).into(), + investor.clone(), + default_investment_id::() + )); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: redeem_amount / 8, + remaining_investment_redeem: redeem_amount / 2, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); - // Cannot transfer more than owned - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - currency_id, - dest_address.clone(), - initial_balance.saturating_add(1), - ), - pallet_liquidity_pools::Error::::BalanceTooLow + let sender = ::Sender::get(); + + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedCollectRedeem { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + currency_payout: redeem_amount / 8, + tranche_tokens_payout: redeem_amount / 2, + remaining_redeem_amount: redeem_amount / 2, + }, + } + .into() + })); + assert!( + !pallet_investments::Pallet::::redemption_requires_collect( + &investor, + default_investment_id::() + ) ); + // Since foreign currency is pool currency, the swap is immediately fulfilled + // and ExecutedCollectRedeem dispatched + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: redeem_amount / 8 + } + .into())); - let pre_total_issuance = orml_tokens::Pallet::::total_issuance(currency_id); + // Process rest of redemption at 50% rate + assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::checked_from_rational(1, 2).unwrap(), + } + )); + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id::(), + ) + .amount, + 0 + ); - assert_ok!(pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - currency_id, - dest_address.clone(), - amount, + // Collect remainder through Investments + assert_ok!(pallet_investments::Pallet::::collect_redemptions_for( + RawOrigin::Signed(Keyring::Alice.into()).into(), + investor.clone(), + default_investment_id::() )); + assert!( + !pallet_investments::Pallet::::redemption_requires_collect( + &investor, + default_investment_id::() + ) + ); + assert!(!frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { + investment_id: default_investment_id::(), + who: investor.clone(), + } + .into() + })); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id::(), + processed_orders: vec![1], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: redeem_amount / 4, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + // Verify collected redemption was burned from investor + assert_eq!(orml_tokens::Pallet::::balance(currency_id, &investor), 0); + assert!(frame_system::Pallet::::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: redeem_amount / 4 + } + .into())); + // Clearing of foreign RedeemState should have been dispatched exactly once + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedCollectRedeem { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + currency_payout: redeem_amount / 4, + tranche_tokens_payout: redeem_amount / 2, + remaining_redeem_amount: 0, + }, + } + .into() + })); + }); + } + + mod should_fail { + use super::*; + + mod decrease_should_underflow { + use super::*; + + #[test_runtimes([development])] + fn invest_decrease_underflow() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let invest_amount: u128 = 10 * decimals(12); + let decrease_amount = invest_amount + 1; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment::( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability::(currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + ), + pallet_foreign_investments::Error::::TooMuchDecrease + ); + }); + } + + #[test_runtimes([development])] + fn redeem_decrease_underflow() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let redeem_amount: u128 = 10 * decimals(12); + let decrease_amount = redeem_amount + 1; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption::( + pool_id, + redeem_amount, + investor.clone(), + currency_id, + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + ), + DispatchError::Arithmetic(sp_runtime::ArithmeticError::Underflow) + ); + }); + } + } + + mod should_throw_requires_collect { + use super::*; + + #[test_runtimes([development])] + fn invest_requires_collect() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount: u128 = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment::( + pool_id, + amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability::(currency_id); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(orml_tokens::Pallet::::mint_into( + currency_id, + &pool_account, + amount + )); + assert_ok!(pallet_investments::Pallet::::process_invest_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: AUSD_ED, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + ), + pallet_investments::Error::::CollectRequired + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg + ), + pallet_investments::Error::::CollectRequired + ); + }); + } + + #[test_runtimes([development])] + fn redeem_requires_collect() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount: u128 = 10 * decimals(12); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool::(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption::( + pool_id, + amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability::(currency_id); + + // Mint more into DomainLocator required for subsequent invest attempt + assert_ok!(orml_tokens::Pallet::::mint_into( + default_investment_id::().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + 1, + )); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(orml_tokens::Pallet::::mint_into( + currency_id, + &pool_account, + amount + )); + assert_ok!(pallet_investments::Pallet::::process_redeem_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::redeem_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + ), + pallet_investments::Error::::CollectRequired + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(currency_id), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg + ), + pallet_investments::Error::::CollectRequired + ); + }); + } + } + + mod payment_payout_currency { + use super::*; + + #[test_runtimes([development])] + fn invalid_invest_payment_currency() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let amount = 6 * decimals(18); + + create_currency_pool::(pool_id, pool_currency, currency_decimals.into()); + do_initial_increase_investment::( + pool_id, + amount, + investor.clone(), + pool_currency, + ); + + enable_usdt_trading::(pool_currency, amount, true, true, true); + + // Should fail to increase, decrease or collect for + // another foreign currency as long as + // `InvestmentState` exists + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: AUSD_ED, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + let collect_msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + collect_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + }); + } + + #[test_runtimes([development])] + fn invalid_redeem_payout_currency() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let amount = 6 * decimals(18); + + create_currency_pool::(pool_id, pool_currency, currency_decimals.into()); + do_initial_increase_redemption::( + pool_id, + amount, + investor.clone(), + pool_currency, + ); + enable_usdt_trading::(pool_currency, amount, true, true, true); + assert_ok!(orml_tokens::Pallet::::mint_into( + default_investment_id::().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount, + )); + + // Should fail to increase, decrease or collect for + // another foreign currency as long as + // `RedemptionState` exists + let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + let collect_msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + collect_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + }); + } + + #[test_runtimes([development])] + fn redeem_payout_currency_not_found() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); + + setup_test(&mut env); + + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let amount = 6 * decimals(18); + + create_currency_pool::(pool_id, pool_currency, currency_decimals.into()); + do_initial_increase_redemption::( + pool_id, + amount, + investor.clone(), + pool_currency, + ); + enable_usdt_trading::(pool_currency, amount, true, true, true); + assert_ok!(orml_tokens::Pallet::::mint_into( + default_investment_id::().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount, + )); + + // Should fail to decrease or collect for another + // foreign currency as long as `RedemptionState` + // exists + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: 1, + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); - assert_eq!( - orml_tokens::Pallet::::total_issuance(currency_id), - pre_total_issuance - amount - ); - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), - initial_balance - amount - ); - }); + let collect_msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + }; + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + collect_msg + ), + pallet_foreign_investments::Error::::MismatchedForeignCurrency + ); + }); + } + } } + } + + mod mismatching_currencies { + use super::*; #[test_runtimes([development])] - fn transfer_non_tranche_tokens_to_local() { + fn collect_foreign_investment_for() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) @@ -4141,56 +3412,111 @@ mod development { setup_test(&mut env); env.parachain_state_mut(|| { - let amount = DEFAULT_BALANCE_GLMR / 2; - let currency_id = AUSD_CURRENCY_ID; - let receiver: AccountId = Keyring::Bob.into(); + let pool_id = POOL_ID; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 6 * decimals(18); + let sending_domain_locator = + Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + let trader: AccountId = Keyring::Alice.into(); + create_currency_pool::(pool_id, pool_currency, pool_currency_decimals.into()); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::Transfer { - currency: general_currency_index::(currency_id), - // sender is irrelevant for other -> local - sender: Keyring::Alice.into(), - receiver: receiver.clone().into(), - amount, - }; + // USDT investment preparations + let invest_amount_foreign_denominated = enable_usdt_trading::( + pool_currency, + invest_amount_pool_denominated, + true, + true, + // not needed because we don't initialize a swap from pool to foreign here + false, + ); - assert_eq!(orml_tokens::Pallet::::total_issuance(currency_id), 0); + // Do first investment and fulfill swap order + do_initial_increase_investment::( + pool_id, + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, + ); + fulfill_swap_into_pool::( + pool_id, + default_order_id::(&investor), + invest_amount_pool_denominated, + invest_amount_foreign_denominated, + trader, + ); - // Finally, verify that we can now transfer the tranche to the destination - // address + // Increase invest order to initialize ForeignInvestmentInfo + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated, + }; assert_ok!(pallet_liquidity_pools::Pallet::::submit( DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg )); - // Verify that the correct amount was minted - assert_eq!( - orml_tokens::Pallet::::total_issuance(currency_id), - amount - ); + // Process 100% of investment at 50% rate (1 pool currency = 2 tranche tokens) + assert_ok!(pallet_investments::Pallet::::process_invest_orders( + default_investment_id::() + )); + assert_ok!(pallet_investments::Pallet::::invest_fulfillment( + default_investment_id::(), + FulfillmentWithPrice { + of_amount: Perquintill::one(), + price: Ratio::checked_from_rational(1, 2).unwrap(), + } + )); + assert_ok!(pallet_investments::Pallet::::collect_investments_for( + RawOrigin::Signed(Keyring::Alice.into()).into(), + investor.clone(), + default_investment_id::() + )); + assert!(orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &investor + ) + .is_zero()); assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &receiver), - amount - ); - - // Verify empty transfers throw - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - LiquidityPoolMessage::Transfer { - currency: general_currency_index::(currency_id), - sender: Keyring::Alice.into(), - receiver: receiver.into(), - amount: 0, - }, + orml_tokens::Pallet::::balance( + default_investment_id::().into(), + &sending_domain_locator ), - pallet_liquidity_pools::Error::::InvalidTransferAmount + invest_amount_pool_denominated * 2 ); + + let sender = ::Sender::get(); + + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedCollectInvest { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + currency_payout: invest_amount_foreign_denominated, + tranche_tokens_payout: 2 * invest_amount_pool_denominated, + remaining_invest_amount: invest_amount_foreign_denominated, + }, + } + .into() + })); }); } + /// Invest in pool currency, then increase in allowed foreign + /// currency, then decrease in same foreign currency multiple times. #[test_runtimes([development])] - fn transfer_tranche_tokens_from_local() { + fn increase_fulfill_increase_decrease_decrease_partial() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) @@ -4201,188 +3527,250 @@ mod development { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let amount = 100_000; - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let receiver = Keyring::Bob; - - // Create the pool - create_ausd_pool::(pool_id); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 6 * decimals(18); + let trader: AccountId = Keyring::Alice.into(); + create_currency_pool::(pool_id, pool_currency, pool_currency_decimals.into()); + + // USDT investment preparations + let invest_amount_foreign_denominated = enable_usdt_trading::( + pool_currency, + invest_amount_pool_denominated, + true, + true, + true, + ); - let tranche_tokens: CurrencyId = cfg_types::tokens::TrancheCurrency::generate( + // Do first investment and fulfill swap order + do_initial_increase_investment::( pool_id, - default_tranche_id::(pool_id), - ) - .into(); - - // Verify that we first need the destination address to be whitelisted - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::UnauthorizedTransfer + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, ); - - // Make receiver the MembersListAdmin of this Pool - assert_ok!(pallet_permissions::Pallet::::add( - ::RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.into(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - let valid_until = u64::MAX; - - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), + fulfill_swap_into_pool::( pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), + default_order_id::(&investor), + invest_amount_pool_denominated, + invest_amount_foreign_denominated, + trader.clone(), ); - // Call the pallet_liquidity_pools::Pallet::::update_member which ensures the - // destination address is whitelisted. - assert_ok!(pallet_liquidity_pools::Pallet::::update_member( - RawOrigin::Signed(receiver.into()).into(), + // Do second investment and not fulfill swap order + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - valid_until, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg )); - // Give receiver enough Tranche balance to be able to transfer it - assert_ok!(orml_tokens::Pallet::::deposit( - tranche_tokens, - &receiver.into(), - amount + // Decrease pending pool swap by same amount + let decrease_msg_pool_swap_amount = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_pool_swap_amount )); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: ::Sender::get(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + currency_payout: invest_amount_foreign_denominated, + remaining_invest_amount: invest_amount_foreign_denominated, + }, + } + .into() + })); - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(receiver.into()).into(), + // Decrease partially investing amount + let decrease_msg_partial_invest_amount = + LiquidityPoolMessage::DecreaseInvestOrder { pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - amount, - ) - ); + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated / 2, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_partial_invest_amount.clone() + )); - // The account to which the tranche should have been transferred - // to on Centrifuge for bookkeeping purposes. - let domain_account: AccountId = Domain::convert(dest_address.domain()); + // Consume entire investing amount by sending same message + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_partial_invest_amount.clone() + )); - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &domain_account), - amount - ); - assert!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver.into()) - .is_zero() - ); + // Swap decreased amount + assert_ok!(pallet_order_book::Pallet::::fill_order( + RawOrigin::Signed(trader.clone()).into(), + default_order_id::(&investor), + invest_amount_pool_denominated + )); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: ::Sender::get(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + currency_payout: invest_amount_foreign_denominated, + remaining_invest_amount: 0, + }, + } + .into() + })); }); } + /// Propagate swaps only via OrderBook fulfillments. + /// + /// Flow: Increase, fulfill, decrease, fulfill #[test_runtimes([development])] - fn transfer_tranche_tokens_to_local() { + fn invest_swaps_happy_path() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) + .add(genesis::tokens::(vec![ + (AUSD_CURRENCY_ID, AUSD_ED), + (USDT_CURRENCY_ID, USDT_ED), + ])) .storage(), ); setup_test(&mut env); env.parachain_state_mut(|| { - // Create new pool let pool_id = POOL_ID; - create_ausd_pool::(pool_id); - - let amount = 100_000_000; - let receiver: AccountId = Keyring::Bob.into(); - let sender: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - let tranche_id = default_tranche_id::(pool_id); - let tranche_tokens: CurrencyId = - cfg_types::tokens::TrancheCurrency::generate(pool_id, tranche_id).into(); - let valid_until = u64::MAX; - - // Fund `DomainLocator` account of origination domain tranche tokens are - // transferred from this account instead of minting - assert_ok!(orml_tokens::Pallet::::mint_into( - tranche_tokens, - &sending_domain_locator, - amount - )); + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let trader: AccountId = Keyring::Alice.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10 * decimals(18); + create_currency_pool::(pool_id, pool_currency, pool_currency_decimals.into()); + let invest_amount_foreign_denominated: u128 = enable_usdt_trading::( + pool_currency, + invest_amount_pool_denominated, + true, + true, + true, + ); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::TransferTrancheTokens { + // Increase such that active swap into USDT is initialized + do_initial_increase_investment::( pool_id, - tranche_id, - sender: sender.address(), - domain: Domain::Centrifuge, - receiver: receiver.clone().into(), - amount, - }; - - // Verify that we first need the receiver to be whitelisted - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - ), - pallet_liquidity_pools::Error::::UnauthorizedTransfer + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, ); - // Make receiver the MembersListAdmin of this Pool - assert_ok!(pallet_permissions::Pallet::::add( - ::RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - crate::generic::utils::pool::give_role::( - receiver.clone(), + // Fulfilling order should propagate it from swapping to investing + let swap_order_id = default_order_id::(&investor); + fulfill_swap_into_pool::( pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), + swap_order_id, + invest_amount_pool_denominated, + invest_amount_foreign_denominated, + trader.clone(), ); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: invest_amount_foreign_denominated, + currency_in: pool_currency, + currency_out: foreign_currency, + ratio: Ratio::one(), + } + .into() + })); - // Finally, verify that we can now transfer the tranche to the destination - // address + // Decrease by half the investment amount + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated / 2, + }; assert_ok!(pallet_liquidity_pools::Pallet::::submit( DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg + msg.clone() )); - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver), - amount - ); - assert!(orml_tokens::Pallet::::free_balance( - tranche_tokens, - &sending_domain_locator - ) - .is_zero()); + let swap_order_id = default_order_id::(&investor); + assert_ok!(pallet_order_book::Pallet::::fill_order( + RawOrigin::Signed(trader.clone()).into(), + swap_order_id, + invest_amount_pool_denominated / 2 + )); + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: invest_amount_pool_denominated / 2, + currency_in: foreign_currency, + currency_out: pool_currency, + ratio: Ratio::one(), + } + .into() + })); + + let sender = ::Sender::get(); + + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: sender.clone(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + currency_payout: invest_amount_foreign_denominated / 2, + remaining_invest_amount: invest_amount_foreign_denominated / 2, + }, + } + .into() + })); }); } - /// Try to transfer tranches for non-existing pools or invalid tranche - /// ids for existing pools. #[test_runtimes([development])] - fn transferring_invalid_tranche_tokens_should_fail() { + fn increase_fulfill_decrease_fulfill_partial_increase() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) @@ -4392,395 +3780,532 @@ mod development { setup_test(&mut env); env.parachain_state_mut(|| { - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - - let valid_pool_id: u64 = 42; - create_ausd_pool::(valid_pool_id); - let valid_tranche_id = default_tranche_id::(valid_pool_id); - let valid_until = u64::MAX; - let transfer_amount = 42; - let invalid_pool_id = valid_pool_id + 1; - let invalid_tranche_id = valid_tranche_id.map(|i| i.saturating_add(1)); - assert!(pallet_pool_system::Pallet::::pool(invalid_pool_id).is_none()); - - // Make Keyring::Bob the MembersListAdmin of both pools - crate::generic::utils::pool::give_role::( - Keyring::Bob.into(), - valid_pool_id, - PoolRole::InvestorAdmin, - ); - crate::generic::utils::pool::give_role::( - Keyring::Bob.into(), - invalid_pool_id, - PoolRole::InvestorAdmin, + let pool_id = POOL_ID; + let investor: AccountId = + AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10 * decimals(18); + let trader: AccountId = Keyring::Alice.into(); + create_currency_pool::(pool_id, pool_currency, pool_currency_decimals.into()); + + // USDT investment preparations + let invest_amount_foreign_denominated = enable_usdt_trading::( + pool_currency, + invest_amount_pool_denominated, + true, + true, + true, ); - // Give Keyring::Bob investor role for (valid_pool_id, invalid_tranche_id) and - // (invalid_pool_id, valid_tranche_id) - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), - invalid_pool_id, - PoolRole::TrancheInvestor(valid_tranche_id, valid_until), - ); - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), - valid_pool_id, - PoolRole::TrancheInvestor(invalid_tranche_id, valid_until), - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Bob.into()).into(), - invalid_pool_id, - valid_tranche_id, - dest_address.clone(), - transfer_amount - ), - pallet_liquidity_pools::Error::::PoolNotFound + // Do first investment and fulfill swap order + do_initial_increase_investment::( + pool_id, + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Bob.into()).into(), - valid_pool_id, - invalid_tranche_id, - dest_address, - transfer_amount - ), - pallet_liquidity_pools::Error::::TrancheNotFound + fulfill_swap_into_pool::( + pool_id, + default_order_id::(&investor), + invest_amount_pool_denominated, + invest_amount_foreign_denominated, + trader.clone(), ); + + // Decrease pending pool swap by same amount + let decrease_msg_pool_swap_amount = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_pool_swap_amount + )); + + // Fulfill decrease swap partially + assert_ok!(pallet_order_book::Pallet::::fill_order( + RawOrigin::Signed(trader.clone()).into(), + default_order_id::(&investor), + 3 * invest_amount_pool_denominated / 4 + )); + + // Increase more than pending swap (pool -> foreign) amount from decrease + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + amount: invest_amount_foreign_denominated / 2, + }; + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + )); + + assert!(frame_system::Pallet::::events().iter().any(|e| { + e.event + == pallet_liquidity_pools_gateway::Event::::OutboundMessageSubmitted { + sender: ::Sender::get(), + domain: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + message: LiquidityPoolMessage::ExecutedDecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id::(pool_id), + investor: investor.clone().into(), + currency: general_currency_index::(foreign_currency), + currency_payout: invest_amount_foreign_denominated, + remaining_invest_amount: invest_amount_foreign_denominated / 2, + }, + } + .into() + })); }); } } +} - mod routers { - use super::*; +mod transfers { + use super::*; - mod axelar_evm { - use std::ops::AddAssign; + #[test_runtimes([development])] + fn transfer_non_tranche_tokens_from_local() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - use super::*; + setup_test(&mut env); - #[test_runtimes([development])] - fn test_via_outbound_queue() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::council_members::(get_council_members())) - .storage(), - ); + env.parachain_state_mut(|| { + let initial_balance = 2 * AUSD_ED; + let amount = initial_balance / 2; + let dest_address = DEFAULT_DOMAIN_ADDRESS_MOONBEAM; + let currency_id = AUSD_CURRENCY_ID; + let source_account = Keyring::Charlie; - let test_domain = Domain::EVM(1); + // Mint sufficient balance + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), + 0 + ); + assert_ok!(orml_tokens::Pallet::::mint_into( + currency_id, + &source_account.into(), + initial_balance + )); + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), + initial_balance + ); - let axelar_contract_address = H160::from_low_u64_be(1); - let axelar_contract_code: Vec = vec![0, 0, 0]; - let axelar_contract_hash = BlakeTwo256::hash_of(&axelar_contract_code); - let liquidity_pools_contract_address = H160::from_low_u64_be(2); + // Only `ForeignAsset` can be transferred + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + CurrencyId::Tranche(42u64, [0u8; 16]), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::InvalidTransferCurrency + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + CurrencyId::Native, + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); - env.parachain_state_mut(|| { - pallet_evm::AccountCodes::::insert( - axelar_contract_address, - axelar_contract_code, - ) - }); + // Cannot transfer as long as cross chain transferability is disabled + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + currency_id, + dest_address.clone(), + initial_balance, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); - let transaction_call_cost = env - .parachain_state(|| ::config().gas_transaction_call); + // Enable LiquidityPools transferability + enable_liquidity_pool_transferability::(currency_id); - let evm_domain = EVMDomain { - target_contract_address: axelar_contract_address, - target_contract_hash: axelar_contract_hash, - fee_values: FeeValues { - value: U256::from(0), - gas_limit: U256::from(transaction_call_cost + 1_000_000), - gas_price: U256::from(10), - }, - }; + // Cannot transfer more than owned + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + currency_id, + dest_address.clone(), + initial_balance.saturating_add(1), + ), + pallet_liquidity_pools::Error::::BalanceTooLow + ); - let axelar_evm_router = AxelarEVMRouter:: { - router: EVMRouter { - evm_domain, - _marker: Default::default(), - }, - evm_chain: BoundedVec::>::try_from( - "ethereum".as_bytes().to_vec(), - ) - .unwrap(), - _marker: Default::default(), - liquidity_pools_contract_address, - }; + let pre_total_issuance = orml_tokens::Pallet::::total_issuance(currency_id); - let test_router = DomainRouter::::AxelarEVM(axelar_evm_router); + assert_ok!(pallet_liquidity_pools::Pallet::::transfer( + RawOrigin::Signed(source_account.into()).into(), + currency_id, + dest_address.clone(), + amount, + )); - env.parachain_state_mut(|| { - assert_ok!( - pallet_liquidity_pools_gateway::Pallet::::set_domain_router( - ::RuntimeOrigin::root(), - test_domain.clone(), - test_router, - ) - ); - }); + assert_eq!( + orml_tokens::Pallet::::total_issuance(currency_id), + pre_total_issuance - amount + ); + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &source_account.into()), + initial_balance - amount + ); + }); + } - let sender = Keyring::Alice.id(); - let gateway_sender = env.parachain_state(|| { - ::Sender::get() - }); + #[test_runtimes([development])] + fn transfer_non_tranche_tokens_to_local() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - let gateway_sender_h160: H160 = H160::from_slice( - &>::as_ref(&gateway_sender) - [0..20], - ); + setup_test(&mut env); - let msg = LiquidityPoolMessage::Transfer { - currency: 0, - sender: Keyring::Alice.id().into(), - receiver: Keyring::Bob.id().into(), - amount: 1_000u128, - }; + env.parachain_state_mut(|| { + let amount = DEFAULT_BALANCE_GLMR / 2; + let currency_id = AUSD_CURRENCY_ID; + let receiver: AccountId = Keyring::Bob.into(); - // Failure - gateway sender account is not funded. - assert_ok!(env.parachain_state_mut(|| { - as OutboundQueue>::submit( - sender.clone(), - test_domain.clone(), - msg.clone(), - ) - })); + // Mock incoming decrease message + let msg = LiquidityPoolMessage::Transfer { + currency: general_currency_index::(currency_id), + // sender is irrelevant for other -> local + sender: Keyring::Alice.into(), + receiver: receiver.clone().into(), + amount, + }; - let mut nonce = T::OutboundMessageNonce::one(); + assert_eq!(orml_tokens::Pallet::::total_issuance(currency_id), 0); - let expected_event = - pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionFailure { - sender: gateway_sender.clone(), - domain: test_domain.clone(), - message: msg.clone(), - error: pallet_evm::Error::::BalanceLow.into(), - nonce, - }; + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - env.pass(Blocks::UntilEvent { - event: expected_event.clone().into(), - limit: 3, - }); + // Verify that the correct amount was minted + assert_eq!( + orml_tokens::Pallet::::total_issuance(currency_id), + amount + ); + assert_eq!( + orml_tokens::Pallet::::free_balance(currency_id, &receiver), + amount + ); - env.check_event(expected_event) - .expect("expected RouterExecutionFailure event"); + // Verify empty transfers throw + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + LiquidityPoolMessage::Transfer { + currency: general_currency_index::(currency_id), + sender: Keyring::Alice.into(), + receiver: receiver.into(), + amount: 0, + }, + ), + pallet_liquidity_pools::Error::::InvalidTransferAmount + ); + }); + } - nonce.add_assign(T::OutboundMessageNonce::one()); + #[test_runtimes([development])] + fn transfer_tranche_tokens_from_local() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - assert_ok!(env.parachain_state_mut(|| { - // Note how both the target address and the gateway sender need to have some - // balance. - crate::generic::utils::evm::mint_balance_into_derived_account::( - axelar_contract_address, - cfg(1_000_000_000), - ); - crate::generic::utils::evm::mint_balance_into_derived_account::( - gateway_sender_h160, - cfg(1_000_000), - ); + setup_test(&mut env); - as OutboundQueue>::submit( - sender.clone(), - test_domain.clone(), - msg.clone(), - ) - })); + env.parachain_state_mut(|| { + let pool_id = POOL_ID; + let amount = 100_000; + let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + let receiver = Keyring::Bob; - let expected_event = - pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { - sender: gateway_sender.clone(), - domain: test_domain.clone(), - message: msg.clone(), - nonce, - }; + // Create the pool + create_ausd_pool::(pool_id); - env.pass(Blocks::UntilEvent { - event: expected_event.clone().into(), - limit: 3, - }); + let tranche_tokens: CurrencyId = cfg_types::tokens::TrancheCurrency::generate( + pool_id, + default_tranche_id::(pool_id), + ) + .into(); - env.check_event(expected_event) - .expect("expected OutboundMessageExecutionSuccess event"); + // Verify that we first need the destination address to be whitelisted + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( + RawOrigin::Signed(Keyring::Alice.into()).into(), + pool_id, + default_tranche_id::(pool_id), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::UnauthorizedTransfer + ); - // Router not found - let unused_domain = Domain::EVM(1234); + // Make receiver the MembersListAdmin of this Pool + assert_ok!(pallet_permissions::Pallet::::add( + ::RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + receiver.into(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); - env.parachain_state_mut(|| { - assert_noop!( - as OutboundQueue>::submit( - sender, - unused_domain.clone(), - msg, - ), - pallet_liquidity_pools_gateway::Error::::RouterNotFound - ); - }); - } - } + // Whitelist destination as TrancheInvestor of this Pool + let valid_until = u64::MAX; - mod ethereum_xcm { - use super::*; + crate::generic::utils::pool::give_role::( + AccountConverter::convert(dest_address.clone()), + pool_id, + PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), + ); - mod utils { - use super::*; + // Call the pallet_liquidity_pools::Pallet::::update_member which ensures the + // destination address is whitelisted. + assert_ok!(pallet_liquidity_pools::Pallet::::update_member( + RawOrigin::Signed(receiver.into()).into(), + pool_id, + default_tranche_id::(pool_id), + dest_address.clone(), + valid_until, + )); - pub fn submit_test_fn( - router_creation_fn: RouterCreationFn, - ) { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); + // Give receiver enough Tranche balance to be able to transfer it + assert_ok!(orml_tokens::Pallet::::deposit( + tranche_tokens, + &receiver.into(), + amount + )); - setup_test(&mut env); + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!( + pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( + RawOrigin::Signed(receiver.into()).into(), + pool_id, + default_tranche_id::(pool_id), + dest_address.clone(), + amount, + ) + ); - enable_para_to_sibling_communication::(&mut env); + // The account to which the tranche should have been transferred + // to on Centrifuge for bookkeeping purposes. + let domain_account: AccountId = Domain::convert(dest_address.domain()); - let msg = Message::::Transfer { - currency: 0, - sender: Keyring::Alice.into(), - receiver: Keyring::Bob.into(), - amount: 1_000u128, - }; + // Verify that the correct amount of the Tranche token was transferred + // to the dest domain account on Centrifuge. + assert_eq!( + orml_tokens::Pallet::::free_balance(tranche_tokens, &domain_account), + amount + ); + assert!( + orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver.into()).is_zero() + ); + }); + } - env.parachain_state_mut(|| { - let domain_router = router_creation_fn( - Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID)).into(), - GLMR_CURRENCY_ID, - ); + #[test_runtimes([development])] + fn transfer_tranche_tokens_to_local() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - assert_ok!( - pallet_liquidity_pools_gateway::Pallet::::set_domain_router( - ::RuntimeOrigin::root(), - TEST_DOMAIN, - domain_router, - ) - ); + setup_test(&mut env); - assert_ok!( - as OutboundQueue>::submit( - Keyring::Alice.into(), - TEST_DOMAIN, - msg.clone(), - ) - ); - }); + env.parachain_state_mut(|| { + // Create new pool + let pool_id = POOL_ID; + create_ausd_pool::(pool_id); + + let amount = 100_000_000; + let receiver: AccountId = Keyring::Bob.into(); + let sender: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + let tranche_id = default_tranche_id::(pool_id); + let tranche_tokens: CurrencyId = + cfg_types::tokens::TrancheCurrency::generate(pool_id, tranche_id).into(); + let valid_until = u64::MAX; + + // Fund `DomainLocator` account of origination domain tranche tokens are + // transferred from this account instead of minting + assert_ok!(orml_tokens::Pallet::::mint_into( + tranche_tokens, + &sending_domain_locator, + amount + )); - let gateway_sender = env.parachain_state(|| { - ::Sender::get() - }); + // Mock incoming decrease message + let msg = LiquidityPoolMessage::TransferTrancheTokens { + pool_id, + tranche_id, + sender: sender.address(), + domain: Domain::Centrifuge, + receiver: receiver.clone().into(), + amount, + }; - let expected_event = - pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { - sender: gateway_sender, - domain: TEST_DOMAIN, - message: msg, - nonce: T::OutboundMessageNonce::one(), - }; + // Verify that we first need the receiver to be whitelisted + assert_noop!( + pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + ), + pallet_liquidity_pools::Error::::UnauthorizedTransfer + ); - env.pass(Blocks::UntilEvent { - event: expected_event.clone().into(), - limit: 3, - }); + // Make receiver the MembersListAdmin of this Pool + assert_ok!(pallet_permissions::Pallet::::add( + ::RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + receiver.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); - env.check_event(expected_event) - .expect("expected OutboundMessageExecutionSuccess event"); - } + // Whitelist destination as TrancheInvestor of this Pool + crate::generic::utils::pool::give_role::( + receiver.clone(), + pool_id, + PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), + ); - type RouterCreationFn = - Box DomainRouter>; - - pub fn get_axelar_xcm_router_fn() -> RouterCreationFn - { - Box::new( - |location: VersionedLocation, currency_id: CurrencyId| -> DomainRouter { - let router = AxelarXCMRouter:: { - router: XCMRouter { - xcm_domain: XcmDomain { - location: Box::new( - location.try_into().expect("Bad xcm domain location"), - ), - ethereum_xcm_transact_call_index: BoundedVec::truncate_from( - vec![38, 0], - ), - contract_address: H160::from_low_u64_be(11), - max_gas_limit: 700_000, - transact_required_weight_at_most: Default::default(), - overall_weight: Default::default(), - fee_currency: currency_id, - fee_amount: decimals(18).saturating_div(5), - }, - _marker: Default::default(), - }, - axelar_target_chain: BoundedVec::< - u8, - ConstU32, - >::try_from( - "ethereum".as_bytes().to_vec() - ) - .unwrap(), - axelar_target_contract: H160::from_low_u64_be(111), - _marker: Default::default(), - }; + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!(pallet_liquidity_pools::Pallet::::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - DomainRouter::AxelarXCM(router) - }, - ) - } + // Verify that the correct amount of the Tranche token was transferred + // to the dest domain account on Centrifuge. + assert_eq!( + orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver), + amount + ); + assert!(orml_tokens::Pallet::::free_balance( + tranche_tokens, + &sending_domain_locator + ) + .is_zero()); + }); + } - pub fn get_ethereum_xcm_router_fn() -> RouterCreationFn - { - Box::new( - |location: VersionedLocation, currency_id: CurrencyId| -> DomainRouter { - let router = EthereumXCMRouter:: { - router: XCMRouter { - xcm_domain: XcmDomain { - location: Box::new( - location.try_into().expect("Bad xcm domain location"), - ), - ethereum_xcm_transact_call_index: BoundedVec::truncate_from( - vec![38, 0], - ), - contract_address: H160::from_low_u64_be(11), - max_gas_limit: 700_000, - transact_required_weight_at_most: Default::default(), - overall_weight: Default::default(), - fee_currency: currency_id, - fee_amount: decimals(18).saturating_div(5), - }, - _marker: Default::default(), - }, - _marker: Default::default(), - }; + /// Try to transfer tranches for non-existing pools or invalid tranche + /// ids for existing pools. + #[test_runtimes([development])] + fn transferring_invalid_tranche_tokens_should_fail() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - DomainRouter::EthereumXCM(router) - }, - ) - } - } + setup_test(&mut env); - use utils::*; + env.parachain_state_mut(|| { + let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + + let valid_pool_id: u64 = 42; + create_ausd_pool::(valid_pool_id); + let valid_tranche_id = default_tranche_id::(valid_pool_id); + let valid_until = u64::MAX; + let transfer_amount = 42; + let invalid_pool_id = valid_pool_id + 1; + let invalid_tranche_id = valid_tranche_id.map(|i| i.saturating_add(1)); + assert!(pallet_pool_system::Pallet::::pool(invalid_pool_id).is_none()); + + // Make Keyring::Bob the MembersListAdmin of both pools + crate::generic::utils::pool::give_role::( + Keyring::Bob.into(), + valid_pool_id, + PoolRole::InvestorAdmin, + ); + crate::generic::utils::pool::give_role::( + Keyring::Bob.into(), + invalid_pool_id, + PoolRole::InvestorAdmin, + ); - const TEST_DOMAIN: Domain = Domain::EVM(1); + // Give Keyring::Bob investor role for (valid_pool_id, invalid_tranche_id) and + // (invalid_pool_id, valid_tranche_id) + crate::generic::utils::pool::give_role::( + AccountConverter::convert(dest_address.clone()), + invalid_pool_id, + PoolRole::TrancheInvestor(valid_tranche_id, valid_until), + ); + crate::generic::utils::pool::give_role::( + AccountConverter::convert(dest_address.clone()), + valid_pool_id, + PoolRole::TrancheInvestor(invalid_tranche_id, valid_until), + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( + RawOrigin::Signed(Keyring::Bob.into()).into(), + invalid_pool_id, + valid_tranche_id, + dest_address.clone(), + transfer_amount + ), + pallet_liquidity_pools::Error::::PoolNotFound + ); + assert_noop!( + pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( + RawOrigin::Signed(Keyring::Bob.into()).into(), + valid_pool_id, + invalid_tranche_id, + dest_address, + transfer_amount + ), + pallet_liquidity_pools::Error::::TrancheNotFound + ); + }); + } +} - #[test_runtimes([development])] - fn submit_ethereum_xcm() { - submit_test_fn::(get_ethereum_xcm_router_fn::()); - } +mod routers { + use super::*; - #[test_runtimes([development])] - fn submit_axelar_xcm() { - submit_test_fn::(get_axelar_xcm_router_fn::()); - } - } - } + mod axelar_evm { + use std::ops::AddAssign; - mod gateway { use super::*; #[test_runtimes([development])] - fn set_domain_router() { + fn test_via_outbound_queue() { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) @@ -4799,12 +4324,15 @@ mod development { pallet_evm::AccountCodes::::insert(axelar_contract_address, axelar_contract_code) }); + let transaction_call_cost = + env.parachain_state(|| ::config().gas_transaction_call); + let evm_domain = EVMDomain { target_contract_address: axelar_contract_address, target_contract_hash: axelar_contract_hash, fee_values: FeeValues { - value: U256::from(10), - gas_limit: U256::from(1_000_000), + value: U256::from(0), + gas_limit: U256::from(transaction_call_cost + 1_000_000), gas_price: U256::from(10), }, }; @@ -4824,497 +4352,448 @@ mod development { let test_router = DomainRouter::::AxelarEVM(axelar_evm_router); - let set_domain_router_call = - set_domain_router_call(test_domain.clone(), test_router.clone()); - - let council_threshold = 2; - let voting_period = 3; - - execute_via_democracy::( - &mut env, - get_council_members(), - set_domain_router_call, - council_threshold, - voting_period, - 0, - 0, - ); - - env.parachain_state(|| { - let router = - pallet_liquidity_pools_gateway::Pallet::::domain_routers(test_domain) - .expect("domain router is set"); - - assert!(router.eq(&test_router)); + env.parachain_state_mut(|| { + assert_ok!( + pallet_liquidity_pools_gateway::Pallet::::set_domain_router( + ::RuntimeOrigin::root(), + test_domain.clone(), + test_router, + ) + ); }); - } - #[test_runtimes([development])] - fn add_remove_instances() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::council_members::(get_council_members())) - .storage(), + let sender = Keyring::Alice.id(); + let gateway_sender = env + .parachain_state(|| ::Sender::get()); + + let gateway_sender_h160: H160 = H160::from_slice( + &>::as_ref(&gateway_sender)[0..20], ); - let test_instance = DomainAddress::EVM(1, [0; 20]); + let msg = LiquidityPoolMessage::Transfer { + currency: 0, + sender: Keyring::Alice.id().into(), + receiver: Keyring::Bob.id().into(), + amount: 1_000u128, + }; - let add_instance_call = add_instance_call::(test_instance.clone()); + // Failure - gateway sender account is not funded. + assert_ok!(env.parachain_state_mut(|| { + as OutboundQueue>::submit( + sender.clone(), + test_domain.clone(), + msg.clone(), + ) + })); - let council_threshold = 2; - let voting_period = 3; + let mut nonce = T::OutboundMessageNonce::one(); - let (prop_index, ref_index) = execute_via_democracy::( - &mut env, - get_council_members(), - add_instance_call, - council_threshold, - voting_period, - 0, - 0, - ); + let expected_event = + pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionFailure { + sender: gateway_sender.clone(), + domain: test_domain.clone(), + message: msg.clone(), + error: pallet_evm::Error::::BalanceLow.into(), + nonce, + }; - env.parachain_state(|| { - assert!( - pallet_liquidity_pools_gateway::Allowlist::::contains_key( - test_instance.domain(), - test_instance.clone() - ) - ); + env.pass(Blocks::UntilEvent { + event: expected_event.clone().into(), + limit: 3, }); - let remove_instance_call = remove_instance_call::(test_instance.clone()); + env.check_event(expected_event) + .expect("expected RouterExecutionFailure event"); - execute_via_democracy::( - &mut env, - get_council_members(), - remove_instance_call, - council_threshold, - voting_period, - prop_index, - ref_index, - ); + nonce.add_assign(T::OutboundMessageNonce::one()); - env.parachain_state(|| { - assert!( - !pallet_liquidity_pools_gateway::Allowlist::::contains_key( - test_instance.domain(), - test_instance.clone() - ) + assert_ok!(env.parachain_state_mut(|| { + // Note how both the target address and the gateway sender need to have some + // balance. + crate::generic::utils::evm::mint_balance_into_derived_account::( + axelar_contract_address, + cfg(1_000_000_000), + ); + crate::generic::utils::evm::mint_balance_into_derived_account::( + gateway_sender_h160, + cfg(1_000_000), ); - }); - } - - #[test_runtimes([development])] - fn process_msg() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .add(genesis::council_members::(get_council_members())) - .storage(), - ); - - let test_instance = DomainAddress::EVM(1, [0; 20]); - - let add_instance_call = add_instance_call::(test_instance.clone()); - - let council_threshold = 2; - let voting_period = 3; - execute_via_democracy::( - &mut env, - get_council_members(), - add_instance_call, - council_threshold, - voting_period, - 0, - 0, - ); + as OutboundQueue>::submit( + sender.clone(), + test_domain.clone(), + msg.clone(), + ) + })); + + let expected_event = + pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { + sender: gateway_sender.clone(), + domain: test_domain.clone(), + message: msg.clone(), + nonce, + }; - env.parachain_state(|| { - assert!( - pallet_liquidity_pools_gateway::Allowlist::::contains_key( - test_instance.domain(), - test_instance.clone() - ) - ); + env.pass(Blocks::UntilEvent { + event: expected_event.clone().into(), + limit: 3, }); - let msg = LiquidityPoolMessage::AddPool { pool_id: 123 }; + env.check_event(expected_event) + .expect("expected OutboundMessageExecutionSuccess event"); - let encoded_msg = msg.serialize(); - - let gateway_msg = BoundedVec::< - u8, - ::MaxIncomingMessageSize, - >::try_from(encoded_msg) - .unwrap(); + // Router not found + let unused_domain = Domain::EVM(1234); env.parachain_state_mut(|| { assert_noop!( - pallet_liquidity_pools_gateway::Pallet::::process_msg( - GatewayOrigin::Domain(test_instance).into(), - gateway_msg, + as OutboundQueue>::submit( + sender, + unused_domain.clone(), + msg, ), - pallet_liquidity_pools::Error::::InvalidIncomingMessage, + pallet_liquidity_pools_gateway::Error::::RouterNotFound ); }); } } -} - -mod centrifuge { - use super::*; - mod utils { + mod ethereum_xcm { use super::*; - /// The test asset id attributed to DOT - pub const DOT_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(91); + mod utils { + use super::*; - pub const LP_ETH_USDC: CurrencyId = CurrencyId::ForeignAsset(100_001); + pub fn submit_test_fn( + router_creation_fn: RouterCreationFn, + ) { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .storage(), + ); - pub const USDC: CurrencyId = CurrencyId::ForeignAsset(6); + setup_test(&mut env); - /// An Asset that is NOT XCM transferable - pub const NO_XCM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(401); + enable_para_to_sibling_communication::(&mut env); - /// 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: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 100_000_000, - location: Some(VersionedLocation::V4(Location::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) - )); - } + let msg = Message::::Transfer { + currency: 0, + sender: Keyring::Alice.into(), + receiver: Keyring::Bob.into(), + amount: 1_000u128, + }; - pub fn register_lp_eth_usdc() { - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000, - location: Some(VersionedLocation::V4(Location::new( - 0, - [ - PalletInstance(103), - GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }), - AccountKey20 { - network: None, - key: hex_literal::hex!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - }, - ], - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - ..CustomMetadata::default() - }, - }; + env.parachain_state_mut(|| { + let domain_router = router_creation_fn( + Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID)).into(), + GLMR_CURRENCY_ID, + ); - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(LP_ETH_USDC) - )); - } + assert_ok!( + pallet_liquidity_pools_gateway::Pallet::::set_domain_router( + ::RuntimeOrigin::root(), + TEST_DOMAIN, + domain_router, + ) + ); - pub fn register_usdc(para_id: u32) { - let meta: AssetMetadata = AssetMetadata { - decimals: 6, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - Junction::Parachain(para_id), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(USDC) - )); - } + assert_ok!( + as OutboundQueue>::submit( + Keyring::Alice.into(), + TEST_DOMAIN, + msg.clone(), + ) + ); + }); - /// Register CFG in the asset registry. - /// It should be executed within an externalities environment. - pub fn register_cfg(para_id: u32) { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V4(Location::new( - 1, - [ - Parachain(para_id), - general_key(parachains::polkadot::centrifuge::CFG_KEY), - ], - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; + let gateway_sender = env.parachain_state(|| { + ::Sender::get() + }); - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); - } + let expected_event = + pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { + sender: gateway_sender, + domain: TEST_DOMAIN, + message: msg, + nonce: T::OutboundMessageNonce::one(), + }; - /// 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: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: Some(VersionedLocation::V2(staging_xcm::v2::MultiLocation::new( - 1, - staging_xcm::v2::Junctions::X2( - staging_xcm::v2::Junction::Parachain(T::FudgeHandle::PARA_ID), - staging_xcm::v2::Junction::GeneralKey( - WeakBoundedVec::>::force_from( - parachains::polkadot::centrifuge::CFG_KEY.into(), - None, - ), - ), - ), - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::Xcm(Default::default()), - ..CustomMetadata::default() - }, - }; + env.pass(Blocks::UntilEvent { + event: expected_event.clone().into(), + limit: 3, + }); - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(CurrencyId::Native) - )); - } + env.check_event(expected_event) + .expect("expected OutboundMessageExecutionSuccess event"); + } - /// Register a token whose `CrossChainTransferability` does NOT include - /// XCM. - pub fn register_no_xcm_token() { - let meta: AssetMetadata = AssetMetadata { - decimals: 18, - name: BoundedVec::default(), - symbol: BoundedVec::default(), - existential_deposit: 1_000_000_000_000, - location: None, - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - ..CustomMetadata::default() - }, - }; + type RouterCreationFn = + Box DomainRouter>; + + pub fn get_axelar_xcm_router_fn() -> RouterCreationFn { + Box::new( + |location: VersionedLocation, currency_id: CurrencyId| -> DomainRouter { + let router = AxelarXCMRouter:: { + router: XCMRouter { + xcm_domain: XcmDomain { + location: Box::new( + location.try_into().expect("Bad xcm domain location"), + ), + ethereum_xcm_transact_call_index: BoundedVec::truncate_from( + vec![38, 0], + ), + contract_address: H160::from_low_u64_be(11), + max_gas_limit: 700_000, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), + fee_currency: currency_id, + fee_amount: decimals(18).saturating_div(5), + }, + _marker: Default::default(), + }, + axelar_target_chain: BoundedVec::< + u8, + ConstU32, + >::try_from("ethereum".as_bytes().to_vec()) + .unwrap(), + axelar_target_contract: H160::from_low_u64_be(111), + _marker: Default::default(), + }; - assert_ok!(orml_asset_registry::Pallet::::register_asset( - ::RuntimeOrigin::root(), - meta, - Some(NO_XCM_ASSET_ID) - )); - } + DomainRouter::AxelarXCM(router) + }, + ) + } - // The fee associated with transferring DOT tokens - pub fn dot_fee() -> Balance { - fee(10) - } + pub fn get_ethereum_xcm_router_fn() -> RouterCreationFn { + Box::new( + |location: VersionedLocation, currency_id: CurrencyId| -> DomainRouter { + let router = EthereumXCMRouter:: { + router: XCMRouter { + xcm_domain: XcmDomain { + location: Box::new( + location.try_into().expect("Bad xcm domain location"), + ), + ethereum_xcm_transact_call_index: BoundedVec::truncate_from( + vec![38, 0], + ), + contract_address: H160::from_low_u64_be(11), + max_gas_limit: 700_000, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), + fee_currency: currency_id, + fee_amount: decimals(18).saturating_div(5), + }, + _marker: Default::default(), + }, + _marker: Default::default(), + }; - pub fn lp_eth_usdc_fee() -> Balance { - fee(6) + DomainRouter::EthereumXCM(router) + }, + ) + } } - pub fn usdc_fee() -> Balance { - fee(6) - } + use utils::*; - pub fn dot(amount: Balance) -> Balance { - amount * decimals(10) - } + const TEST_DOMAIN: Domain = Domain::EVM(1); - pub fn lp_eth_usdc(amount: Balance) -> Balance { - amount * decimals(6) + #[test_runtimes([development])] + fn submit_ethereum_xcm() { + submit_test_fn::(get_ethereum_xcm_router_fn::()); } - pub fn usdc(amount: Balance) -> Balance { - amount * decimals(6) + #[test_runtimes([development])] + fn submit_axelar_xcm() { + submit_test_fn::(get_axelar_xcm_router_fn::()); } + } +} - pub fn foreign(amount: Balance, num_decimals: u32) -> Balance { - amount * decimals(num_decimals) - } +mod gateway { + use super::*; - pub fn transfer_dot_from_relay_chain(env: &mut FudgeEnv) { - let alice_initial_dot = dot(10); - let transfer_amount: Balance = dot(3); + #[test_runtimes([development])] + fn set_domain_router() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::council_members::(get_council_members())) + .storage(), + ); - env.parachain_state_mut(|| { - register_dot::(); - assert_eq!( - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.into()), - 0 - ); - }); + let test_domain = Domain::EVM(1); - env.relay_state_mut(|| { - assert_ok!( - pallet_balances::Pallet::>::force_set_balance( - as frame_system::Config>::RuntimeOrigin::root(), - as frame_system::Config>::Lookup::unlookup( - Keyring::Alice.id() - ), - alice_initial_dot, - ) - ); + let axelar_contract_address = H160::from_low_u64_be(1); + let axelar_contract_code: Vec = vec![0, 0, 0]; + let axelar_contract_hash = BlakeTwo256::hash_of(&axelar_contract_code); + let liquidity_pools_contract_address = H160::from_low_u64_be(2); - assert_ok!( - pallet_xcm::Pallet::>::force_xcm_version( - as frame_system::Config>::RuntimeOrigin::root(), - Box::new(Location::new( - 0, - Junction::Parachain(T::FudgeHandle::PARA_ID), - )), - XCM_VERSION, - ) - ); + env.parachain_state_mut(|| { + pallet_evm::AccountCodes::::insert(axelar_contract_address, axelar_contract_code) + }); - 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 - ) - ); + let evm_domain = EVMDomain { + target_contract_address: axelar_contract_address, + target_contract_hash: axelar_contract_hash, + fee_values: FeeValues { + value: U256::from(10), + gas_limit: U256::from(1_000_000), + gas_price: U256::from(10), + }, + }; - assert_eq!( - pallet_balances::Pallet::>::free_balance( - &Keyring::Alice.into() - ), - 69867666991 // Comes from alice_initial_dot - transfer_amount with noise - ); - }); + let axelar_evm_router = AxelarEVMRouter:: { + router: EVMRouter { + evm_domain, + _marker: Default::default(), + }, + evm_chain: BoundedVec::>::try_from( + "ethereum".as_bytes().to_vec(), + ) + .unwrap(), + _marker: Default::default(), + liquidity_pools_contract_address, + }; - env.pass(Blocks::ByNumber(2)); + let test_router = DomainRouter::::AxelarEVM(axelar_evm_router); - env.parachain_state(|| { - assert_eq!( - orml_tokens::Pallet::::free_balance(DOT_ASSET_ID, &Keyring::Alice.into()), - 29919630000 // Comes from `transfer_amount - dot_fee()` with some noise - ); - }); - } - } + let set_domain_router_call = + set_domain_router_call(test_domain.clone(), test_router.clone()); - mod restricted_transfers { - use cfg_types::tokens::FilterCurrency; + let council_threshold = 2; + let voting_period = 3; - use super::*; - use crate::generic::{ - envs::runtime_env::RuntimeEnv, - utils::currency::{default_metadata, CurrencyInfo, CustomCurrency}, - }; + execute_via_democracy::( + &mut env, + get_council_members(), + set_domain_router_call, + council_threshold, + voting_period, + 0, + 0, + ); - const TRANSFER: u32 = 10; - const CHAIN_ID: u64 = 1; - const CONTRACT_ACCOUNT: [u8; 20] = [1; 20]; + env.parachain_state(|| { + let router = pallet_liquidity_pools_gateway::Pallet::::domain_routers(test_domain) + .expect("domain router is set"); - #[test_runtimes(all)] - fn restrict_lp_eth_transfer() { - let pallet_index = T::PalletInfo::index::>(); - let curr = CustomCurrency( - CurrencyId::ForeignAsset(1), - AssetMetadata { - decimals: 6, - location: Some(VersionedLocation::V4(Location::new( - 0, - [ - PalletInstance(pallet_index.unwrap() as u8), - GlobalConsensus(NetworkId::Ethereum { chain_id: CHAIN_ID }), - AccountKey20 { - network: None, - key: CONTRACT_ACCOUNT, - }, - ], - ))), - additional: CustomMetadata { - transferability: CrossChainTransferability::LiquidityPools, - ..CustomMetadata::default() - }, - ..default_metadata() - }, + assert!(router.eq(&test_router)); + }); + } + + #[test_runtimes([development])] + fn add_remove_instances() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::council_members::(get_council_members())) + .storage(), + ); + + let test_instance = DomainAddress::EVM(1, [0; 20]); + + let add_instance_call = add_instance_call::(test_instance.clone()); + + let council_threshold = 2; + let voting_period = 3; + + let (prop_index, ref_index) = execute_via_democracy::( + &mut env, + get_council_members(), + add_instance_call, + council_threshold, + voting_period, + 0, + 0, + ); + + env.parachain_state(|| { + assert!( + pallet_liquidity_pools_gateway::Allowlist::::contains_key( + test_instance.domain(), + test_instance.clone() + ) ); + }); - let mut env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(10))) - .add(genesis::tokens::([(curr.id(), curr.val(TRANSFER))])) - .add(genesis::assets::([(curr.id(), curr.metadata())])) - .storage(), + let remove_instance_call = remove_instance_call::(test_instance.clone()); + + execute_via_democracy::( + &mut env, + get_council_members(), + remove_instance_call, + council_threshold, + voting_period, + prop_index, + ref_index, + ); + + env.parachain_state(|| { + assert!( + !pallet_liquidity_pools_gateway::Allowlist::::contains_key( + test_instance.domain(), + test_instance.clone() + ) ); + }); + } - env.parachain_state_mut(|| { - let curr_contract = DomainAddress::EVM(CHAIN_ID, CONTRACT_ACCOUNT); + #[test_runtimes([development])] + fn process_msg() { + let mut env = FudgeEnv::::from_parachain_storage( + Genesis::default() + .add(genesis::balances::(cfg(1_000))) + .add(genesis::council_members::(get_council_members())) + .storage(), + ); + + let test_instance = DomainAddress::EVM(1, [0; 20]); + + let add_instance_call = add_instance_call::(test_instance.clone()); + + let council_threshold = 2; + let voting_period = 3; + + execute_via_democracy::( + &mut env, + get_council_members(), + add_instance_call, + council_threshold, + voting_period, + 0, + 0, + ); + + env.parachain_state(|| { + assert!( + pallet_liquidity_pools_gateway::Allowlist::::contains_key( + test_instance.domain(), + test_instance.clone() + ) + ); + }); - assert_ok!( - pallet_transfer_allowlist::Pallet::::add_transfer_allowance( - RawOrigin::Signed(Keyring::Alice.into()).into(), - FilterCurrency::Specific(curr.id()), - RestrictedTransferLocation::Address(curr_contract.clone()), - ) - ); + let msg = LiquidityPoolMessage::AddPool { pool_id: 123 }; - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - curr.id(), - DomainAddress::EVM(CHAIN_ID, [2; 20]), // Not the allowed contract account - curr.val(TRANSFER), - ), - pallet_transfer_allowlist::Error::::NoAllowanceForDestination - ); + let encoded_msg = msg.serialize(); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(Keyring::Alice.into()).into(), - curr.id(), - curr_contract, - curr.val(TRANSFER), - ), - // But it's ok, we do not care about the router transaction in this context. - // Is already checked at `liquidity_pools.rs` - pallet_liquidity_pools_gateway::Error::::RouterNotFound - ); - }); - } + let gateway_msg = BoundedVec::< + u8, + ::MaxIncomingMessageSize, + >::try_from(encoded_msg) + .unwrap(); + + env.parachain_state_mut(|| { + assert_noop!( + pallet_liquidity_pools_gateway::Pallet::::process_msg( + GatewayOrigin::Domain(test_instance).into(), + gateway_msg, + ), + pallet_liquidity_pools::Error::::InvalidIncomingMessage, + ); + }); } } diff --git a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs index 6eb8e6ef6d..3d7725c20a 100644 --- a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs @@ -23,8 +23,7 @@ use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::PalletI use runtime_common::remarks::Remark; use sp_runtime::traits::Zero; use staging_xcm::{ - prelude::XCM_VERSION, - v4::{Junction::*, Junctions::*, Location, NetworkId}, + v4::{Junction::*, Location, NetworkId}, VersionedLocation, }; diff --git a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs index e1caeeab7d..4c15fb61b7 100644 --- a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs @@ -7,7 +7,7 @@ use crate::{ generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport, RelayRuntime}, utils::{ currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, @@ -25,8 +25,6 @@ use crate::{ const INITIAL: u32 = 100; const TRANSFER: u32 = 20; -type Relay = FudgeRelayRuntime; - fn create_transfeable_currency(decimals: u32, para_id: Option) -> CustomCurrency { CustomCurrency( CurrencyId::ForeignAsset(1), @@ -169,7 +167,7 @@ fn para_from_to_relay_using_relay_native_tokens() { let mut env = FudgeEnv::::from_storage( Genesis::default() - .add(genesis::balances::>(curr.val(INITIAL))) + .add(genesis::balances::>(curr.val(INITIAL))) .storage(), Genesis::default() .add(genesis::assets::([(curr.id(), curr.metadata())])) @@ -181,16 +179,18 @@ fn para_from_to_relay_using_relay_native_tokens() { enable_relay_to_para_communication::(&mut env); env.relay_state_mut(|| { - assert_ok!(pallet_xcm::Pallet::>::reserve_transfer_assets( - RawOrigin::Signed(Keyring::Alice.id()).into(), - Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), - account_location(0, None, Keyring::Bob.id()), - Box::new((Here, curr.val(TRANSFER)).into()), - 0, - )); + assert_ok!( + pallet_xcm::Pallet::>::reserve_transfer_assets( + RawOrigin::Signed(Keyring::Alice.id()).into(), + Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), + account_location(0, None, Keyring::Bob.id()), + Box::new((Here, curr.val(TRANSFER)).into()), + 0, + ) + ); assert_eq!( - pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), + pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), (curr.val(INITIAL) - curr.val(TRANSFER)).approx(0.01) ); }); @@ -226,7 +226,7 @@ fn para_from_to_relay_using_relay_native_tokens() { env.relay_state(|| { assert_eq!( - pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), + pallet_balances::Pallet::>::free_balance(&Keyring::Alice.id()), (curr.val(INITIAL) - curr.val(TRANSFER) + curr.val(TRANSFER / 2)).approx(0.01) ); }); diff --git a/runtime/integration-tests/src/generic/envs/fudge_env.rs b/runtime/integration-tests/src/generic/envs/fudge_env.rs index 6233784e47..4c9cc28d0c 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env.rs @@ -24,7 +24,7 @@ pub trait FudgeSupport: Runtime { type FudgeHandle: FudgeHandle; } -pub type FudgeRelayRuntime = <::FudgeHandle as FudgeHandle>::RelayRuntime; +pub type RelayRuntime = <::FudgeHandle as FudgeHandle>::RelayRuntime; /// Evironment that uses fudge to interact with the runtime pub struct FudgeEnv { diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index 5d20f93a47..28e4be79ef 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -11,19 +11,17 @@ use staging_xcm::{ use crate::generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeRelayRuntime, FudgeSupport}, + envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport, RelayRuntime}, utils::currency::default_metadata, }; pub fn enable_relay_to_para_communication(env: &mut FudgeEnv) { env.relay_state_mut(|| { - assert_ok!( - pallet_xcm::Pallet::>::force_xcm_version( - RawOrigin::Root.into(), - Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), - XCM_VERSION, - ) - ); + assert_ok!(pallet_xcm::Pallet::>::force_xcm_version( + RawOrigin::Root.into(), + Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), + XCM_VERSION, + )); }); } @@ -48,19 +46,22 @@ pub fn enable_para_to_sibling_communication(env: &mut env.relay_state_mut(|| { // Enable para -> sibling comunication though relay - assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< - FudgeRelayRuntime, - >::force_open_hrmp_channel( - RawOrigin::Root.into(), - Id::from(T::FudgeHandle::PARA_ID), - Id::from(T::FudgeHandle::SIBLING_ID), - 10, - 1024, - )); + assert_ok!( + polkadot_runtime_parachains::hrmp::Pallet::>::force_open_hrmp_channel( + RawOrigin::Root.into(), + Id::from(T::FudgeHandle::PARA_ID), + Id::from(T::FudgeHandle::SIBLING_ID), + 10, + 1024, + ) + ); - assert_ok!(polkadot_runtime_parachains::hrmp::Pallet::< - FudgeRelayRuntime, - >::force_process_hrmp_open(RawOrigin::Root.into(), 1)); + assert_ok!( + polkadot_runtime_parachains::hrmp::Pallet::>::force_process_hrmp_open( + RawOrigin::Root.into(), + 1 + ) + ); }); env.pass(Blocks::ByNumber(1)); From 5a832ad57f6aacf31b3f1a7a9fd50d4ba9236e19 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Mon, 17 Jun 2024 08:42:45 +0200 Subject: [PATCH 15/21] removed re-added tranche tokens tests --- .../src/generic/cases/liquidity_pools.rs | 320 +----------------- 1 file changed, 2 insertions(+), 318 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index cef47d70ef..31022ab729 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -3871,6 +3871,8 @@ mod foreign_investments { mod transfers { use super::*; + // TODO: Must be moved to lp/transfers.rs (?) + #[test_runtimes([development])] fn transfer_non_tranche_tokens_from_local() { let mut env = FudgeEnv::::from_parachain_storage( @@ -3976,324 +3978,6 @@ mod transfers { ); }); } - - #[test_runtimes([development])] - fn transfer_non_tranche_tokens_to_local() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let amount = DEFAULT_BALANCE_GLMR / 2; - let currency_id = AUSD_CURRENCY_ID; - let receiver: AccountId = Keyring::Bob.into(); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::Transfer { - currency: general_currency_index::(currency_id), - // sender is irrelevant for other -> local - sender: Keyring::Alice.into(), - receiver: receiver.clone().into(), - amount, - }; - - assert_eq!(orml_tokens::Pallet::::total_issuance(currency_id), 0); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify that the correct amount was minted - assert_eq!( - orml_tokens::Pallet::::total_issuance(currency_id), - amount - ); - assert_eq!( - orml_tokens::Pallet::::free_balance(currency_id, &receiver), - amount - ); - - // Verify empty transfers throw - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - LiquidityPoolMessage::Transfer { - currency: general_currency_index::(currency_id), - sender: Keyring::Alice.into(), - receiver: receiver.into(), - amount: 0, - }, - ), - pallet_liquidity_pools::Error::::InvalidTransferAmount - ); - }); - } - - #[test_runtimes([development])] - fn transfer_tranche_tokens_from_local() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = POOL_ID; - let amount = 100_000; - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let receiver = Keyring::Bob; - - // Create the pool - create_ausd_pool::(pool_id); - - let tranche_tokens: CurrencyId = cfg_types::tokens::TrancheCurrency::generate( - pool_id, - default_tranche_id::(pool_id), - ) - .into(); - - // Verify that we first need the destination address to be whitelisted - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Alice.into()).into(), - pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::UnauthorizedTransfer - ); - - // Make receiver the MembersListAdmin of this Pool - assert_ok!(pallet_permissions::Pallet::::add( - ::RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.into(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - let valid_until = u64::MAX; - - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), - pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), - ); - - // Call the pallet_liquidity_pools::Pallet::::update_member which ensures the - // destination address is whitelisted. - assert_ok!(pallet_liquidity_pools::Pallet::::update_member( - RawOrigin::Signed(receiver.into()).into(), - pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - valid_until, - )); - - // Give receiver enough Tranche balance to be able to transfer it - assert_ok!(orml_tokens::Pallet::::deposit( - tranche_tokens, - &receiver.into(), - amount - )); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(receiver.into()).into(), - pool_id, - default_tranche_id::(pool_id), - dest_address.clone(), - amount, - ) - ); - - // The account to which the tranche should have been transferred - // to on Centrifuge for bookkeeping purposes. - let domain_account: AccountId = Domain::convert(dest_address.domain()); - - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &domain_account), - amount - ); - assert!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver.into()).is_zero() - ); - }); - } - - #[test_runtimes([development])] - fn transfer_tranche_tokens_to_local() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - // Create new pool - let pool_id = POOL_ID; - create_ausd_pool::(pool_id); - - let amount = 100_000_000; - let receiver: AccountId = Keyring::Bob.into(); - let sender: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - let tranche_id = default_tranche_id::(pool_id); - let tranche_tokens: CurrencyId = - cfg_types::tokens::TrancheCurrency::generate(pool_id, tranche_id).into(); - let valid_until = u64::MAX; - - // Fund `DomainLocator` account of origination domain tranche tokens are - // transferred from this account instead of minting - assert_ok!(orml_tokens::Pallet::::mint_into( - tranche_tokens, - &sending_domain_locator, - amount - )); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::TransferTrancheTokens { - pool_id, - tranche_id, - sender: sender.address(), - domain: Domain::Centrifuge, - receiver: receiver.clone().into(), - amount, - }; - - // Verify that we first need the receiver to be whitelisted - assert_noop!( - pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg.clone() - ), - pallet_liquidity_pools::Error::::UnauthorizedTransfer - ); - - // Make receiver the MembersListAdmin of this Pool - assert_ok!(pallet_permissions::Pallet::::add( - ::RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - crate::generic::utils::pool::give_role::( - receiver.clone(), - pool_id, - PoolRole::TrancheInvestor(default_tranche_id::(pool_id), valid_until), - ); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!(pallet_liquidity_pools::Pallet::::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - orml_tokens::Pallet::::free_balance(tranche_tokens, &receiver), - amount - ); - assert!(orml_tokens::Pallet::::free_balance( - tranche_tokens, - &sending_domain_locator - ) - .is_zero()); - }); - } - - /// Try to transfer tranches for non-existing pools or invalid tranche - /// ids for existing pools. - #[test_runtimes([development])] - fn transferring_invalid_tranche_tokens_should_fail() { - let mut env = FudgeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(cfg(1_000))) - .storage(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - - let valid_pool_id: u64 = 42; - create_ausd_pool::(valid_pool_id); - let valid_tranche_id = default_tranche_id::(valid_pool_id); - let valid_until = u64::MAX; - let transfer_amount = 42; - let invalid_pool_id = valid_pool_id + 1; - let invalid_tranche_id = valid_tranche_id.map(|i| i.saturating_add(1)); - assert!(pallet_pool_system::Pallet::::pool(invalid_pool_id).is_none()); - - // Make Keyring::Bob the MembersListAdmin of both pools - crate::generic::utils::pool::give_role::( - Keyring::Bob.into(), - valid_pool_id, - PoolRole::InvestorAdmin, - ); - crate::generic::utils::pool::give_role::( - Keyring::Bob.into(), - invalid_pool_id, - PoolRole::InvestorAdmin, - ); - - // Give Keyring::Bob investor role for (valid_pool_id, invalid_tranche_id) and - // (invalid_pool_id, valid_tranche_id) - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), - invalid_pool_id, - PoolRole::TrancheInvestor(valid_tranche_id, valid_until), - ); - crate::generic::utils::pool::give_role::( - AccountConverter::convert(dest_address.clone()), - valid_pool_id, - PoolRole::TrancheInvestor(invalid_tranche_id, valid_until), - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Bob.into()).into(), - invalid_pool_id, - valid_tranche_id, - dest_address.clone(), - transfer_amount - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - RawOrigin::Signed(Keyring::Bob.into()).into(), - valid_pool_id, - invalid_tranche_id, - dest_address, - transfer_amount - ), - pallet_liquidity_pools::Error::::TrancheNotFound - ); - }); - } } mod routers { From de3760aacfc399ece8d906b84a89b99b272c6270 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Mon, 17 Jun 2024 09:49:19 +0200 Subject: [PATCH 16/21] remove fudge from proxy tests --- .../src/generic/cases/liquidity_pools.rs | 2 +- .../src/generic/cases/proxy.rs | 170 ++++++++---------- 2 files changed, 80 insertions(+), 92 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 31022ab729..22ca3c7a13 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -3871,7 +3871,7 @@ mod foreign_investments { mod transfers { use super::*; - // TODO: Must be moved to lp/transfers.rs (?) + // TODO: Must be moved to lp/transfers.rs (?) or to UT? It seems more an UT. #[test_runtimes([development])] fn transfer_non_tranche_tokens_from_local() { diff --git a/runtime/integration-tests/src/generic/cases/proxy.rs b/runtime/integration-tests/src/generic/cases/proxy.rs index 8fa276a305..a1ce753c5e 100644 --- a/runtime/integration-tests/src/generic/cases/proxy.rs +++ b/runtime/integration-tests/src/generic/cases/proxy.rs @@ -1,4 +1,3 @@ -use cfg_primitives::Balance; use cfg_types::tokens::{AssetMetadata, CurrencyId}; use frame_support::{assert_err, assert_ok}; use frame_system::RawOrigin; @@ -9,14 +8,11 @@ use crate::{ generic::{ config::Runtime, env::Env, - envs::{ - fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, - runtime_env::RuntimeEnv, - }, + envs::runtime_env::RuntimeEnv, utils::{ - currency::{cfg, usd6, CurrencyInfo, CustomCurrency, Usd6}, + currency::{cfg, CurrencyInfo, CustomCurrency}, genesis::{self, Genesis}, - xcm::{account_location, enable_para_to_sibling_communication, transferable_metadata}, + xcm::{account_location, transferable_metadata}, }, }, utils::accounts::Keyring, @@ -26,87 +22,73 @@ const FROM: Keyring = Keyring::Charlie; const PROXY: Keyring = Keyring::Alice; const TO: Keyring = Keyring::Bob; -const FOR_FEES: Balance = cfg(1); -const TRANSFER_AMOUNT: Balance = usd6(100); -const INITIAL: Balance = usd6(1000) + TRANSFER_AMOUNT; - -fn configure_proxy_and_transfer(proxy_type: T::ProxyType) -> DispatchResult { - let env = RuntimeEnv::::from_parachain_storage( - Genesis::default() - .add(genesis::balances::(FOR_FEES)) - .add(genesis::tokens::(vec![(Usd6.id(), INITIAL)])) - .storage(), - ); - - let call = pallet_restricted_tokens::Call::transfer { - currency_id: Usd6.id(), - amount: TRANSFER_AMOUNT, - dest: T::Lookup::unlookup(TO.id()), - } - .into(); - - configure_proxy_and_call::(env, proxy_type, call) +enum TransferKind { + Local, + Xcm, } -fn configure_proxy_and_x_transfer( - proxy_type: T::ProxyType, -) -> DispatchResult { +fn run_test(proxy_type: T::ProxyType, transfer_kind: TransferKind) -> DispatchResult { + let para_id = 1234; let curr = CustomCurrency( CurrencyId::ForeignAsset(1), AssetMetadata { decimals: 6, - ..transferable_metadata(Some(T::FudgeHandle::PARA_ID)) + ..transferable_metadata(Some(para_id)) }, ); - let mut env = FudgeEnv::::from_parachain_storage( + let mut env = RuntimeEnv::::from_parachain_storage( Genesis::default() - .add(genesis::balances::(FOR_FEES)) - .add(genesis::tokens::(vec![(curr.id(), INITIAL)])) + .add(genesis::balances::(cfg(1))) // For fees + .add(genesis::tokens::(vec![(curr.id(), curr.val(1000))])) .add(genesis::assets::(vec![(curr.id(), curr.metadata())])) .storage(), ); - enable_para_to_sibling_communication::(&mut env); - - let call = pallet_restricted_xtokens::Call::transfer { - currency_id: curr.id(), - amount: TRANSFER_AMOUNT, - dest: account_location(1, Some(T::FudgeHandle::SIBLING_ID), TO.id()), - dest_weight_limit: WeightLimit::Unlimited, - } - .into(); - - configure_proxy_and_call::(env, proxy_type, call) -} + let call = match transfer_kind { + TransferKind::Local => pallet_restricted_tokens::Call::transfer { + currency_id: curr.id(), + amount: curr.val(100), + dest: T::Lookup::unlookup(TO.id()), + } + .into(), + TransferKind::Xcm => pallet_restricted_xtokens::Call::transfer { + currency_id: curr.id(), + amount: curr.val(100), + dest: account_location(1, Some(para_id), TO.id()), + dest_weight_limit: WeightLimit::Unlimited, + } + .into(), + }; -fn configure_proxy_and_call( - mut env: impl Env, - proxy_type: T::ProxyType, - call: T::RuntimeCallExt, -) -> DispatchResult { env.parachain_state_mut(|| { // Register PROXY as proxy of FROM - pallet_proxy::Pallet::::add_proxy( + assert_ok!(pallet_proxy::Pallet::::add_proxy( RawOrigin::Signed(FROM.id()).into(), T::Lookup::unlookup(PROXY.id()), proxy_type, 0, - ) - .unwrap(); + )); // Acts as FROM using PROXY - pallet_proxy::Pallet::::proxy( + assert_ok!(pallet_proxy::Pallet::::proxy( RawOrigin::Signed(PROXY.id()).into(), T::Lookup::unlookup(FROM.id()), None, Box::new(call), - ) - .unwrap(); + )); }); env.find_event(|e| match e { - pallet_proxy::Event::::ProxyExecuted { result } => Some(result), + pallet_proxy::Event::::ProxyExecuted { result } => { + if result == Err(orml_xtokens::Error::::XcmExecutionFailed.into()) { + // We have not configured XCM, so if we reach the sending phase though xcm we + // can assert that proxy was filtered correctly. + Some(Ok(())) + } else { + Some(result) + } + } _ => None, }) .unwrap() @@ -117,8 +99,9 @@ fn development_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_transfer::( - development_runtime::ProxyType::Transfer + assert_ok!(run_test::( + development_runtime::ProxyType::Transfer, + TransferKind::Local )); } @@ -128,7 +111,7 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(development_runtime::ProxyType::Borrow), + run_test::(development_runtime::ProxyType::Borrow, TransferKind::Local), frame_system::Error::::CallFiltered, ); } @@ -139,39 +122,40 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(development_runtime::ProxyType::Invest), + run_test::(development_runtime::ProxyType::Invest, TransferKind::Local), frame_system::Error::::CallFiltered, ); } #[test_runtimes([development])] -fn development_x_transfer_with_proxy_transfer() +fn development_x_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_x_transfer::( - development_runtime::ProxyType::Transfer + assert_ok!(run_test::( + development_runtime::ProxyType::Transfer, + TransferKind::Xcm )); } #[test_runtimes([development])] -fn development_x_transfer_with_proxy_borrow() +fn development_x_transfer_with_proxy_borrow() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(development_runtime::ProxyType::Borrow), + run_test::(development_runtime::ProxyType::Borrow, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } #[test_runtimes([development])] -fn development_x_transfer_with_proxy_invest() +fn development_x_transfer_with_proxy_invest() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(development_runtime::ProxyType::Invest), + run_test::(development_runtime::ProxyType::Invest, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } @@ -181,8 +165,9 @@ fn altair_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_transfer::( - altair_runtime::ProxyType::Transfer + assert_ok!(run_test::( + altair_runtime::ProxyType::Transfer, + TransferKind::Local )); } @@ -192,7 +177,7 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(altair_runtime::ProxyType::Borrow), + run_test::(altair_runtime::ProxyType::Borrow, TransferKind::Local), frame_system::Error::::CallFiltered, ); } @@ -203,39 +188,40 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(altair_runtime::ProxyType::Invest), + run_test::(altair_runtime::ProxyType::Invest, TransferKind::Local), frame_system::Error::::CallFiltered, ); } #[test_runtimes([altair])] -fn altair_x_transfer_with_proxy_transfer() +fn altair_x_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_x_transfer::( - altair_runtime::ProxyType::Transfer + assert_ok!(run_test::( + altair_runtime::ProxyType::Transfer, + TransferKind::Xcm )); } #[test_runtimes([altair])] -fn altair_x_transfer_with_proxy_borrow() +fn altair_x_transfer_with_proxy_borrow() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(altair_runtime::ProxyType::Borrow), + run_test::(altair_runtime::ProxyType::Borrow, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } #[test_runtimes([altair])] -fn altair_x_transfer_with_proxy_invest() +fn altair_x_transfer_with_proxy_invest() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(altair_runtime::ProxyType::Invest), + run_test::(altair_runtime::ProxyType::Invest, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } @@ -245,8 +231,9 @@ fn centrifuge_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_transfer::( - centrifuge_runtime::ProxyType::Transfer + assert_ok!(run_test::( + centrifuge_runtime::ProxyType::Transfer, + TransferKind::Local )); } @@ -256,7 +243,7 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(centrifuge_runtime::ProxyType::Borrow), + run_test::(centrifuge_runtime::ProxyType::Borrow, TransferKind::Local), frame_system::Error::::CallFiltered, ); } @@ -267,39 +254,40 @@ where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_transfer::(centrifuge_runtime::ProxyType::Invest), + run_test::(centrifuge_runtime::ProxyType::Invest, TransferKind::Local), frame_system::Error::::CallFiltered, ); } #[test_runtimes([centrifuge])] -fn centrifuge_x_transfer_with_proxy_transfer() +fn centrifuge_x_transfer_with_proxy_transfer() where T: pallet_proxy::Config, { - assert_ok!(configure_proxy_and_x_transfer::( - centrifuge_runtime::ProxyType::Transfer + assert_ok!(run_test::( + centrifuge_runtime::ProxyType::Transfer, + TransferKind::Xcm )); } #[test_runtimes([centrifuge])] -fn centrifuge_x_transfer_with_proxy_borrow() +fn centrifuge_x_transfer_with_proxy_borrow() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(centrifuge_runtime::ProxyType::Borrow), + run_test::(centrifuge_runtime::ProxyType::Borrow, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } #[test_runtimes([centrifuge])] -fn centrifuge_x_transfer_with_proxy_invest() +fn centrifuge_x_transfer_with_proxy_invest() where T: pallet_proxy::Config, { assert_err!( - configure_proxy_and_x_transfer::(centrifuge_runtime::ProxyType::Invest), + run_test::(centrifuge_runtime::ProxyType::Invest, TransferKind::Xcm), frame_system::Error::::CallFiltered, ); } From abace1f8bebe4e65809a0e4dbb07505ae6785449 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Mon, 17 Jun 2024 15:56:09 +0200 Subject: [PATCH 17/21] minor cleans --- .../integration-tests/src/generic/cases/liquidity_pools.rs | 1 - runtime/integration-tests/src/generic/cases/lp/mod.rs | 7 +++++-- .../integration-tests/src/generic/cases/lp/transfers.rs | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 22ca3c7a13..e5b68df34c 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -3993,7 +3993,6 @@ mod routers { let mut env = FudgeEnv::::from_parachain_storage( Genesis::default() .add(genesis::balances::(cfg(1_000))) - .add(genesis::council_members::(get_council_members())) .storage(), ); diff --git a/runtime/integration-tests/src/generic/cases/lp/mod.rs b/runtime/integration-tests/src/generic/cases/lp/mod.rs index d10a514f0b..af012b585d 100644 --- a/runtime/integration-tests/src/generic/cases/lp/mod.rs +++ b/runtime/integration-tests/src/generic/cases/lp/mod.rs @@ -162,11 +162,14 @@ pub mod utils { } pub fn verify_outbound_success( - _: ::Message, + message: ::Message, ) { assert!(matches!( last_event::>(), - pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { .. } + pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { + message: message, + .. + } )); } diff --git a/runtime/integration-tests/src/generic/cases/lp/transfers.rs b/runtime/integration-tests/src/generic/cases/lp/transfers.rs index af772f9f56..864f3f43c0 100644 --- a/runtime/integration-tests/src/generic/cases/lp/transfers.rs +++ b/runtime/integration-tests/src/generic/cases/lp/transfers.rs @@ -143,13 +143,13 @@ fn transfer_tokens_from_local() { utils::prepare_hold_usdc_local::(&mut env); env.state_mut(|_evm| { - let call = pallet_liquidity_pools::Pallet::::transfer( + pallet_liquidity_pools::Pallet::::transfer( OriginFor::::signed(Keyring::Ferdie.into()), USDC.id(), DomainAddress::evm(EVM_DOMAIN_CHAIN_ID, Keyring::Ferdie.into()), AMOUNT, - ); - call.unwrap(); + ) + .unwrap(); lp::utils::process_outbound::(lp::utils::verify_outbound_success::); }); From a2f7119ccbbb1a85d91717d8373080e8361bd590 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 18 Jun 2024 10:17:54 +0200 Subject: [PATCH 18/21] fix warnings --- runtime/integration-tests/src/generic/cases/lp/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/lp/mod.rs b/runtime/integration-tests/src/generic/cases/lp/mod.rs index af012b585d..87669e43ec 100644 --- a/runtime/integration-tests/src/generic/cases/lp/mod.rs +++ b/runtime/integration-tests/src/generic/cases/lp/mod.rs @@ -167,9 +167,9 @@ pub mod utils { assert!(matches!( last_event::>(), pallet_liquidity_pools_gateway::Event::::OutboundMessageExecutionSuccess { - message: message, + message: processed_message, .. - } + } if processed_message == message )); } From d24c686706189f8ec9efc1aa7b4cd663dd6caa8b Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 20 Jun 2024 15:29:20 +0200 Subject: [PATCH 19/21] decouple PARA_ID and SIBLING_ID from FudgeHandle --- .../src/generic/cases/liquidity_pools.rs | 10 +++++----- .../src/generic/cases/xcm_transfers.rs | 19 +++++++++++-------- .../src/generic/envs/fudge_env/handle.rs | 5 ++--- .../integration-tests/src/generic/impls.rs | 19 +++++-------------- .../src/generic/utils/xcm.rs | 13 ++++++++----- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index e5b68df34c..19985385f8 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -51,7 +51,7 @@ use crate::{ generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport}, + envs::fudge_env::{handle::SIBLING_ID, FudgeEnv, FudgeSupport}, utils::{ democracy::execute_via_democracy, genesis, genesis::Genesis, xcm::enable_para_to_sibling_communication, @@ -108,7 +108,7 @@ mod utils { location: Some(VersionedLocation::V4(Location::new( 1, [ - Parachain(T::FudgeHandle::SIBLING_ID), + Parachain(SIBLING_ID), general_key(parachains::kusama::karura::AUSD_KEY), ], ))), @@ -212,7 +212,7 @@ mod utils { existential_deposit: GLMR_ED, location: Some(VersionedLocation::V4(Location::new( 1, - [Parachain(T::FudgeHandle::SIBLING_ID), general_key(&[0, 1])], + [Parachain(SIBLING_ID), general_key(&[0, 1])], ))), additional: CustomMetadata { transferability: CrossChainTransferability::Xcm(Default::default()), @@ -348,7 +348,7 @@ mod utils { set_test_domain_router::( MOONBEAM_EVM_CHAIN_ID, - Location::new(1, Junction::Parachain(T::FudgeHandle::SIBLING_ID)).into(), + Location::new(1, Junction::Parachain(SIBLING_ID)).into(), GLMR_CURRENCY_ID, ); }); @@ -4169,7 +4169,7 @@ mod routers { env.parachain_state_mut(|| { let domain_router = router_creation_fn( - Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID)).into(), + Location::new(1, Parachain(SIBLING_ID)).into(), GLMR_CURRENCY_ID, ); diff --git a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs index 4c15fb61b7..2a1b7e8504 100644 --- a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs @@ -7,7 +7,10 @@ use crate::{ generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport, RelayRuntime}, + envs::fudge_env::{ + handle::{PARA_ID, SIBLING_ID}, + FudgeEnv, FudgeSupport, RelayRuntime, + }, utils::{ currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, @@ -37,7 +40,7 @@ fn create_transfeable_currency(decimals: u32, para_id: Option) -> CustomCur #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_foreign_tokens() { - let curr = create_transfeable_currency(6, Some(T::FudgeHandle::PARA_ID)); + let curr = create_transfeable_currency(6, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -57,7 +60,7 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), curr.id(), curr.val(TRANSFER), - account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), + account_location(1, Some(SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -79,7 +82,7 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { #[test_runtimes(all)] fn para_to_sibling_with_native_to_foreign_tokens() { - let curr = create_transfeable_currency(18, Some(T::FudgeHandle::PARA_ID)); + let curr = create_transfeable_currency(18, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -99,7 +102,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), Native, cfg(TRANSFER), - account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), + account_location(1, Some(SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -121,7 +124,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_native_tokens() { - let curr = create_transfeable_currency(18, Some(T::FudgeHandle::PARA_ID)); + let curr = create_transfeable_currency(18, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -141,7 +144,7 @@ fn para_to_sibling_with_foreign_to_native_tokens() { RawOrigin::Signed(Keyring::Alice.id()).into(), curr.id(), curr.val(TRANSFER), - account_location(1, Some(T::FudgeHandle::SIBLING_ID), Keyring::Bob.id()), + account_location(1, Some(SIBLING_ID), Keyring::Bob.id()), WeightLimit::Unlimited, )); @@ -182,7 +185,7 @@ fn para_from_to_relay_using_relay_native_tokens() { assert_ok!( pallet_xcm::Pallet::>::reserve_transfer_assets( RawOrigin::Signed(Keyring::Alice.id()).into(), - Box::new(Parachain(T::FudgeHandle::PARA_ID).into()), + Box::new(Parachain(PARA_ID).into()), account_location(0, None, Keyring::Bob.id()), Box::new((Here, curr.val(TRANSFER)).into()), 0, 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 5bb99eafc2..07d3af10e7 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env/handle.rs @@ -32,6 +32,8 @@ use crate::generic::config::Runtime; /// Start date used for timestamps in test-enviornments /// Sat Jan 01 2022 00:00:00 GMT+0000 pub const START_DATE: u64 = 1640995200u64; +pub const PARA_ID: u32 = 1001; +pub const SIBLING_ID: u32 = 1002; type InherentCreator = Box< dyn CreateInherentDataProviders< @@ -118,9 +120,6 @@ 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; diff --git a/runtime/integration-tests/src/generic/impls.rs b/runtime/integration-tests/src/generic/impls.rs index 764c40ee27..8c0791ac0d 100644 --- a/runtime/integration-tests/src/generic/impls.rs +++ b/runtime/integration-tests/src/generic/impls.rs @@ -46,8 +46,6 @@ macro_rules! impl_fudge_support { $relay_path:ident, $relay_session_keys:expr, $parachain_path:ident, - $parachain_id:literal, - $sibling_id:literal ) => { const _: () = { use fudge::primitives::{Chain, ParaId}; @@ -58,6 +56,7 @@ macro_rules! impl_fudge_support { use crate::generic::envs::fudge_env::{ handle::{ FudgeHandle, ParachainBuilder, ParachainClient, RelayClient, RelaychainBuilder, + PARA_ID, SIBLING_ID, }, FudgeSupport, }; @@ -67,11 +66,11 @@ macro_rules! impl_fudge_support { #[fudge::relaychain] pub relay: RelaychainBuilder<$relay_path::RuntimeApi, $relay_path::Runtime>, - #[fudge::parachain($parachain_id)] + #[fudge::parachain(PARA_ID)] pub parachain: ParachainBuilder<$parachain_path::Block, $parachain_path::RuntimeApi>, - #[fudge::parachain($sibling_id)] + #[fudge::parachain(SIBLING_ID)] pub sibling: ParachainBuilder<$parachain_path::Block, $parachain_path::RuntimeApi>, } @@ -91,9 +90,7 @@ 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, @@ -102,12 +99,12 @@ macro_rules! impl_fudge_support { ) -> Self { let relay = Self::new_relay_builder(relay_storage, $relay_session_keys); let parachain = Self::new_parachain_builder( - ParaId::from(Self::PARA_ID), + ParaId::from(PARA_ID), &relay, parachain_storage, ); let sibling = Self::new_parachain_builder( - ParaId::from(Self::SIBLING_ID), + ParaId::from(SIBLING_ID), &relay, sibling_storage, ); @@ -183,8 +180,6 @@ impl_fudge_support!( rococo_runtime, default_rococo_session_keys(), development_runtime, - 2000, - 2001 ); impl_fudge_support!( @@ -192,8 +187,6 @@ impl_fudge_support!( rococo_runtime, default_rococo_session_keys(), altair_runtime, - 2088, - 2089 ); impl_fudge_support!( @@ -201,8 +194,6 @@ impl_fudge_support!( rococo_runtime, default_rococo_session_keys(), centrifuge_runtime, - 2031, - 2032 ); pub fn default_rococo_session_keys() -> rococo_runtime::SessionKeys { diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index 28e4be79ef..9f6b4d7f07 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -11,7 +11,10 @@ use staging_xcm::{ use crate::generic::{ config::Runtime, env::{Blocks, Env}, - envs::fudge_env::{handle::FudgeHandle, FudgeEnv, FudgeSupport, RelayRuntime}, + envs::fudge_env::{ + handle::{PARA_ID, SIBLING_ID}, + FudgeEnv, FudgeSupport, RelayRuntime, + }, utils::currency::default_metadata, }; @@ -19,7 +22,7 @@ pub fn enable_relay_to_para_communication(env: &mut F env.relay_state_mut(|| { assert_ok!(pallet_xcm::Pallet::>::force_xcm_version( RawOrigin::Root.into(), - Box::new(Location::new(0, Parachain(T::FudgeHandle::PARA_ID))), + Box::new(Location::new(0, Parachain(PARA_ID))), XCM_VERSION, )); }); @@ -39,7 +42,7 @@ pub fn enable_para_to_sibling_communication(env: &mut env.parachain_state_mut(|| { assert_ok!(pallet_xcm::Pallet::::force_xcm_version( RawOrigin::Root.into(), - Box::new(Location::new(1, Parachain(T::FudgeHandle::SIBLING_ID))), + Box::new(Location::new(1, Parachain(SIBLING_ID))), XCM_VERSION, )); }); @@ -49,8 +52,8 @@ pub fn enable_para_to_sibling_communication(env: &mut assert_ok!( polkadot_runtime_parachains::hrmp::Pallet::>::force_open_hrmp_channel( RawOrigin::Root.into(), - Id::from(T::FudgeHandle::PARA_ID), - Id::from(T::FudgeHandle::SIBLING_ID), + Id::from(PARA_ID), + Id::from(SIBLING_ID), 10, 1024, ) From cce79b646aa8f6518505d36ea1504fcbc9311a4c Mon Sep 17 00:00:00 2001 From: lemunozm Date: Mon, 24 Jun 2024 12:27:24 +0200 Subject: [PATCH 20/21] revert liquidity-pool changes --- .../src/generic/cases/liquidity_pools.rs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 9383cede21..860c1468e4 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -65,7 +65,6 @@ use staging_xcm::{ }, VersionedAsset, VersionedAssets, VersionedLocation, }; -use utils::*; use crate::{ generic::{ @@ -212,9 +211,9 @@ pub mod utils { } } -mod development { - use utils::*; +use utils::*; +mod development { use super::*; pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(4); @@ -799,6 +798,8 @@ mod development { } } + use utils::*; + mod add_allow_upgrade { use cfg_types::tokens::LiquidityPoolsWrappedToken; @@ -4527,8 +4528,6 @@ mod development { } mod ethereum_xcm { - use utils::*; - use super::*; mod utils { @@ -4668,6 +4667,8 @@ mod development { } } + use utils::*; + const TEST_DOMAIN: Domain = Domain::EVM(1); #[test_runtimes([development])] @@ -4872,12 +4873,11 @@ mod development { mod altair { use altair_runtime::{xcm::CurrencyIdConvert, PoolPalletIndex}; - use utils::*; - - use super::*; pub const KSM_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1000); + use super::*; + mod utils { use super::*; @@ -4949,6 +4949,8 @@ mod altair { } } + use utils::*; + mod transfers { use super::*; @@ -5843,7 +5845,6 @@ mod altair { mod centrifuge { use centrifuge_runtime::xcm::CurrencyIdConvert; - use utils::*; use super::*; @@ -6119,6 +6120,8 @@ mod centrifuge { } } + use utils::*; + mod asset_registry { use super::*; From 3991dea6746e37cf41e8c97458cdc7f208ebb911 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Mon, 24 Jun 2024 15:51:20 +0200 Subject: [PATCH 21/21] William suggestions --- libs/primitives/src/lib.rs | 1 + .../src/generic/cases/xcm_transfers.rs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libs/primitives/src/lib.rs b/libs/primitives/src/lib.rs index d92a92bc3d..cf1ad99966 100644 --- a/libs/primitives/src/lib.rs +++ b/libs/primitives/src/lib.rs @@ -284,6 +284,7 @@ pub mod constants { /// The maximum number of pool fees per pool fee bucket pub const MAX_POOL_FEES_PER_BUCKET: u32 = 100; + /// Identification of the native token of the chain. Used in XCM locations. pub const NATIVE_KEY: &[u8] = &[0, 1]; } diff --git a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs index 2a1b7e8504..04f471144b 100644 --- a/runtime/integration-tests/src/generic/cases/xcm_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/xcm_transfers.rs @@ -28,7 +28,7 @@ use crate::{ const INITIAL: u32 = 100; const TRANSFER: u32 = 20; -fn create_transfeable_currency(decimals: u32, para_id: Option) -> CustomCurrency { +fn create_transferable_currency(decimals: u32, para_id: Option) -> CustomCurrency { CustomCurrency( CurrencyId::ForeignAsset(1), AssetMetadata { @@ -40,7 +40,7 @@ fn create_transfeable_currency(decimals: u32, para_id: Option) -> CustomCur #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_foreign_tokens() { - let curr = create_transfeable_currency(6, Some(PARA_ID)); + let curr = create_transferable_currency(6, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -82,7 +82,7 @@ fn para_to_sibling_with_foreign_to_foreign_tokens() { #[test_runtimes(all)] fn para_to_sibling_with_native_to_foreign_tokens() { - let curr = create_transfeable_currency(18, Some(PARA_ID)); + let curr = create_transferable_currency(18, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -124,7 +124,7 @@ fn para_to_sibling_with_native_to_foreign_tokens() { #[test_runtimes(all)] fn para_to_sibling_with_foreign_to_native_tokens() { - let curr = create_transfeable_currency(18, Some(PARA_ID)); + let curr = create_transferable_currency(18, Some(PARA_ID)); let mut env = FudgeEnv::::from_storage( Default::default(), @@ -166,7 +166,7 @@ fn para_to_sibling_with_foreign_to_native_tokens() { #[test_runtimes(all)] fn para_from_to_relay_using_relay_native_tokens() { - let curr = create_transfeable_currency(10, None); + let curr = create_transferable_currency(10, None); let mut env = FudgeEnv::::from_storage( Genesis::default()