From 47384e9c3f8b4f2669396622f3cf90459abfa526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Mu=C3=B1oz=20Mart=C3=ADn?= Date: Tue, 25 Jun 2024 09:59:13 +0200 Subject: [PATCH] Liquidity-pools: Add unitary tests (#1879) * prepare mock for UTs and simplify some minor things * normal function instead of Convert trait * rename into_account_id() to evm_to_account() * add UTs for transfer * simplify account conversion * remove unused CurrencyIdOf * remove already covered tests * remove democracy utils * apply Cosmin suggestions * add transfer_tranche_tokens tests * minor clean * add add_pool tests * add add_tranche tests * check balance post transfers * fix lp tests * fix imports after rebasing --- Cargo.lock | 9 +- .../src/{try_convert.rs => converter.rs} | 18 +- libs/mocks/src/foreign_investment.rs | 159 +++++ libs/mocks/src/lib.rs | 5 +- libs/mocks/src/outbound_queue.rs | 37 + libs/types/src/domain_address.rs | 36 +- libs/types/src/tokens.rs | 12 + pallets/liquidity-pools-gateway/src/mock.rs | 12 +- pallets/liquidity-pools/Cargo.toml | 47 +- pallets/liquidity-pools/src/contract.rs | 63 -- pallets/liquidity-pools/src/hooks.rs | 6 +- pallets/liquidity-pools/src/inbound.rs | 6 +- pallets/liquidity-pools/src/lib.rs | 167 ++--- pallets/liquidity-pools/src/mock.rs | 141 ++++ pallets/liquidity-pools/src/routers.rs | 35 - pallets/liquidity-pools/src/tests.rs | 632 ++++++++++++++++++ runtime/altair/src/lib.rs | 2 - runtime/centrifuge/src/lib.rs | 2 - runtime/common/src/account_conversion.rs | 25 +- runtime/common/src/gateway.rs | 2 +- runtime/common/src/xcm.rs | 35 +- runtime/development/src/lib.rs | 2 - .../src/generic/cases/assets.rs | 6 +- .../src/generic/cases/currency_conversions.rs | 4 +- .../src/generic/cases/liquidity_pools.rs | 547 ++------------- .../src/generic/cases/lp/transfers.rs | 51 +- .../src/generic/cases/restricted_transfers.rs | 5 +- .../src/generic/utils/currency.rs | 11 - .../src/generic/utils/democracy.rs | 276 -------- .../src/generic/utils/mod.rs | 1 - .../src/generic/utils/xcm.rs | 5 +- .../integration-tests/src/utils/accounts.rs | 3 +- 32 files changed, 1207 insertions(+), 1155 deletions(-) rename libs/mocks/src/{try_convert.rs => converter.rs} (64%) create mode 100644 libs/mocks/src/foreign_investment.rs create mode 100644 libs/mocks/src/outbound_queue.rs delete mode 100644 pallets/liquidity-pools/src/contract.rs create mode 100644 pallets/liquidity-pools/src/mock.rs delete mode 100644 pallets/liquidity-pools/src/routers.rs create mode 100644 pallets/liquidity-pools/src/tests.rs delete mode 100644 runtime/integration-tests/src/generic/utils/democracy.rs diff --git a/Cargo.lock b/Cargo.lock index 18559e03f9..5f272b6ec9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8215,22 +8215,16 @@ dependencies = [ name = "pallet-liquidity-pools" version = "0.0.1" dependencies = [ + "cfg-mocks", "cfg-primitives", "cfg-traits", "cfg-types", "cfg-utils", - "ethabi", - "fp-self-contained", - "frame-benchmarking", "frame-support", "frame-system", "hex", "orml-tokens", "orml-traits", - "pallet-balances", - "pallet-ethereum", - "pallet-timestamp", - "pallet-uniques", "parity-scale-codec", "scale-info", "sp-core", @@ -8238,7 +8232,6 @@ dependencies = [ "sp-runtime", "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.7.2)", "staging-xcm", - "xcm-primitives", ] [[package]] diff --git a/libs/mocks/src/try_convert.rs b/libs/mocks/src/converter.rs similarity index 64% rename from libs/mocks/src/try_convert.rs rename to libs/mocks/src/converter.rs index 99fc901812..4882151717 100644 --- a/libs/mocks/src/try_convert.rs +++ b/libs/mocks/src/converter.rs @@ -3,14 +3,12 @@ pub mod pallet { use cfg_traits::TryConvert; use frame_support::pallet_prelude::*; use mock_builder::{execute_call_instance, register_call_instance}; + use sp_runtime::traits::Convert; #[pallet::config] pub trait Config: frame_system::Config { type From; - type To; - - type Error; } #[pallet::pallet] @@ -20,16 +18,26 @@ pub mod pallet { type CallIds, I: 'static = ()> = StorageMap<_, _, String, mock_builder::CallId>; impl, I: 'static> Pallet { - pub fn mock_try_convert(f: impl Fn(T::From) -> Result + 'static) { + pub fn mock_try_convert(f: impl Fn(T::From) -> Result + 'static) { + register_call_instance!(f); + } + + pub fn mock_convert(f: impl Fn(T::From) -> T::To + 'static) { register_call_instance!(f); } } impl, I: 'static> TryConvert for Pallet { - type Error = T::Error; + type Error = DispatchError; fn try_convert(from: T::From) -> Result { execute_call_instance!(from) } } + + impl, I: 'static> Convert for Pallet { + fn convert(from: T::From) -> T::To { + execute_call_instance!(from) + } + } } diff --git a/libs/mocks/src/foreign_investment.rs b/libs/mocks/src/foreign_investment.rs new file mode 100644 index 0000000000..8dd0471caa --- /dev/null +++ b/libs/mocks/src/foreign_investment.rs @@ -0,0 +1,159 @@ +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use cfg_traits::investments::ForeignInvestment; + use frame_support::pallet_prelude::*; + use mock_builder::{execute_call, register_call}; + + #[pallet::config] + pub trait Config: frame_system::Config { + type Amount; + type TrancheAmount; + type CurrencyId; + type InvestmentId; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + type CallIds = StorageMap<_, _, String, mock_builder::CallId>; + + impl Pallet { + pub fn mock_increase_foreign_investment( + f: impl Fn(&T::AccountId, T::InvestmentId, T::Amount, T::CurrencyId) -> DispatchResult + + 'static, + ) { + register_call!(move |(a, b, c, d)| f(a, b, c, d)); + } + + pub fn mock_decrease_foreign_investment( + f: impl Fn(&T::AccountId, T::InvestmentId, T::Amount, T::CurrencyId) -> DispatchResult + + 'static, + ) { + register_call!(move |(a, b, c, d)| f(a, b, c, d)); + } + + pub fn mock_increase_foreign_redemption( + f: impl Fn( + &T::AccountId, + T::InvestmentId, + T::TrancheAmount, + T::CurrencyId, + ) -> DispatchResult + + 'static, + ) { + register_call!(move |(a, b, c, d)| f(a, b, c, d)); + } + + pub fn mock_decrease_foreign_redemption( + f: impl Fn( + &T::AccountId, + T::InvestmentId, + T::TrancheAmount, + T::CurrencyId, + ) -> DispatchResult + + 'static, + ) { + register_call!(move |(a, b, c, d)| f(a, b, c, d)); + } + + pub fn mock_collect_foreign_investment( + f: impl Fn(&T::AccountId, T::InvestmentId, T::CurrencyId) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } + + pub fn mock_collect_foreign_redemption( + f: impl Fn(&T::AccountId, T::InvestmentId, T::CurrencyId) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } + + pub fn mock_investment( + f: impl Fn(&T::AccountId, T::InvestmentId) -> Result + 'static, + ) { + register_call!(move |(a, b)| f(a, b)); + } + + pub fn mock_redemption( + f: impl Fn(&T::AccountId, T::InvestmentId) -> Result + + 'static, + ) { + register_call!(move |(a, b)| f(a, b)); + } + } + + impl ForeignInvestment for Pallet { + type Amount = T::Amount; + type CurrencyId = T::CurrencyId; + type Error = DispatchError; + type InvestmentId = T::InvestmentId; + type TrancheAmount = T::TrancheAmount; + + fn increase_foreign_investment( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::Amount, + d: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c, d)) + } + + fn decrease_foreign_investment( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::Amount, + d: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c, d)) + } + + fn increase_foreign_redemption( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::TrancheAmount, + d: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c, d)) + } + + fn decrease_foreign_redemption( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::TrancheAmount, + d: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c, d)) + } + + fn collect_foreign_investment( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c)) + } + + fn collect_foreign_redemption( + a: &T::AccountId, + b: Self::InvestmentId, + c: Self::CurrencyId, + ) -> DispatchResult { + execute_call!((a, b, c)) + } + + fn investment( + a: &T::AccountId, + b: Self::InvestmentId, + ) -> Result { + execute_call!((a, b)) + } + + fn redemption( + a: &T::AccountId, + b: Self::InvestmentId, + ) -> Result { + execute_call!((a, b)) + } + } +} diff --git a/libs/mocks/src/lib.rs b/libs/mocks/src/lib.rs index eec8873049..de52496021 100644 --- a/libs/mocks/src/lib.rs +++ b/libs/mocks/src/lib.rs @@ -1,11 +1,14 @@ pub mod asset_registry; pub mod change_guard; +pub mod converter; pub mod currency_conversion; pub mod data; pub mod fees; +pub mod foreign_investment; pub mod investment; pub mod liquidity_pools; pub mod liquidity_pools_gateway_routers; +pub mod outbound_queue; pub mod pay_fee; pub mod permissions; pub mod pools; @@ -14,7 +17,6 @@ pub mod rewards; pub mod status_notification; pub mod time; pub mod token_swaps; -pub mod try_convert; pub mod value_provider; pub mod write_off_policy; @@ -33,7 +35,6 @@ pub use rewards::pallet as pallet_mock_rewards; pub use status_notification::pallet as pallet_mock_status_notification; pub use time::pallet as pallet_mock_time; pub use token_swaps::pallet as pallet_mock_token_swaps; -pub use try_convert::pallet as pallet_mock_try_convert; pub use value_provider::pallet as pallet_mock_value_provider; pub use write_off_policy::pallet as pallet_mock_write_off_policy; diff --git a/libs/mocks/src/outbound_queue.rs b/libs/mocks/src/outbound_queue.rs new file mode 100644 index 0000000000..986f4acd55 --- /dev/null +++ b/libs/mocks/src/outbound_queue.rs @@ -0,0 +1,37 @@ +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use cfg_traits::liquidity_pools::OutboundQueue; + use frame_support::pallet_prelude::*; + use mock_builder::{execute_call, register_call}; + + #[pallet::config] + pub trait Config: frame_system::Config { + type Sender; + type Destination; + type Message; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + type CallIds = StorageMap<_, _, String, mock_builder::CallId>; + + impl Pallet { + pub fn mock_submit( + f: impl Fn(T::Sender, T::Destination, T::Message) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } + } + + impl OutboundQueue for Pallet { + type Destination = T::Destination; + type Message = T::Message; + type Sender = T::Sender; + + fn submit(a: Self::Sender, b: Self::Destination, c: Self::Message) -> DispatchResult { + execute_call!((a, b, c)) + } + } +} diff --git a/libs/types/src/domain_address.rs b/libs/types/src/domain_address.rs index dc450b683a..f3a19eb094 100644 --- a/libs/types/src/domain_address.rs +++ b/libs/types/src/domain_address.rs @@ -15,7 +15,7 @@ use cfg_utils::{decode_be_bytes, vec_to_fixed_array}; use frame_support::pallet_prelude::RuntimeDebug; use parity_scale_codec::{Decode, Encode, Input, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::traits::{AccountIdConversion, Convert}; +use sp_runtime::traits::AccountIdConversion; use sp_std::{vec, vec::Vec}; use crate::EVMChainId; @@ -63,12 +63,12 @@ impl Codec for Domain { } } -impl Convert for Domain -where - AccountId: Encode + Decode, -{ - fn convert(domain: Domain) -> AccountId { - DomainLocator { domain }.into_account_truncating() +impl Domain { + pub fn into_account(&self) -> AccountId { + DomainLocator { + domain: self.clone(), + } + .into_account_truncating() } } @@ -118,3 +118,25 @@ impl DomainAddress { self.clone().into() } } + +#[cfg(test)] +mod tests { + use parity_scale_codec::{Decode, Encode}; + + use super::*; + + #[test] + fn test_domain_encode_decode() { + test_domain_identity(Domain::Centrifuge); + test_domain_identity(Domain::EVM(1284)); + test_domain_identity(Domain::EVM(1)); + } + + /// Test that (decode . encode) results in the original value + fn test_domain_identity(domain: Domain) { + let encoded = domain.encode(); + let decoded = Domain::decode(&mut encoded.as_slice()).unwrap(); + + assert_eq!(domain, decoded); + } +} diff --git a/libs/types/src/tokens.rs b/libs/types/src/tokens.rs index 77c2737b2a..824e6a5608 100644 --- a/libs/types/src/tokens.rs +++ b/libs/types/src/tokens.rs @@ -321,6 +321,18 @@ pub struct CustomMetadata { pub local_representation: Option, } +#[cfg(feature = "std")] +pub fn default_metadata() -> AssetMetadata { + AssetMetadata { + decimals: 0, + name: Default::default(), + symbol: Default::default(), + existential_deposit: 0, + location: None, + additional: Default::default(), + } +} + /// The Cross Chain Transferability property of an asset describes the way(s), /// if any, that said asset is cross-chain transferable. It may currently be /// transferable through Xcm, Centrifuge Liquidity Pools, or All . diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index b99959e456..4f0f2c78de 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -1,13 +1,10 @@ -use cfg_mocks::{ - pallet_mock_liquidity_pools, pallet_mock_routers, pallet_mock_try_convert, MessageMock, - RouterMock, -}; +use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_routers, MessageMock, RouterMock}; use cfg_primitives::OutboundMessageNonce; use cfg_types::domain_address::DomainAddress; use frame_support::derive_impl; use frame_system::EnsureRoot; use sp_core::{crypto::AccountId32, ConstU128, H256}; -use sp_runtime::{traits::IdentityLookup, BuildStorage, DispatchError}; +use sp_runtime::{traits::IdentityLookup, BuildStorage}; use crate::{pallet as pallet_liquidity_pools_gateway, EnsureLocal}; @@ -26,7 +23,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, MockLiquidityPools: pallet_mock_liquidity_pools, MockRouters: pallet_mock_routers, - MockOriginRecovery: pallet_mock_try_convert, + MockOriginRecovery: cfg_mocks::converter::pallet, LiquidityPoolsGateway: pallet_liquidity_pools_gateway, } ); @@ -55,8 +52,7 @@ impl pallet_mock_liquidity_pools::Config for Runtime { impl pallet_mock_routers::Config for Runtime {} -impl pallet_mock_try_convert::Config for Runtime { - type Error = DispatchError; +impl cfg_mocks::converter::pallet::Config for Runtime { type From = (Vec, Vec); type To = DomainAddress; } diff --git a/pallets/liquidity-pools/Cargo.toml b/pallets/liquidity-pools/Cargo.toml index 1bbbad918b..a5c8dfbf01 100644 --- a/pallets/liquidity-pools/Cargo.toml +++ b/pallets/liquidity-pools/Cargo.toml @@ -13,24 +13,16 @@ documentation.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ethabi = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } hex = { workspace = true } orml-traits = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } - -# Substrate crates -sp-core = { workspace = true } - -# Optional dependencies for benchmarking -frame-benchmarking = { workspace = true, optional = true } -orml-tokens = { workspace = true, optional = true } -pallet-balances = { workspace = true, optional = true } -pallet-uniques = { workspace = true, optional = true } +staging-xcm = { workspace = true } # Our custom pallets cfg-primitives = { workspace = true } @@ -38,27 +30,16 @@ cfg-traits = { workspace = true } cfg-types = { workspace = true } cfg-utils = { workspace = true } -# Polkadot -staging-xcm = { workspace = true } - -fp-self-contained = { workspace = true } -pallet-ethereum = { workspace = true } -xcm-primitives = { workspace = true } - [dev-dependencies] -hex = { workspace = true, default-features = true } - -# Substrate crates & pallets -pallet-balances = { workspace = true } -pallet-timestamp = { workspace = true } -pallet-uniques = { workspace = true } -sp-core = { workspace = true } +cfg-mocks = { workspace = true, default-features = true } +orml-tokens = { workspace = true, default-features = true } sp-io = { workspace = true } [features] default = ["std"] std = [ "parity-scale-codec/std", + "cfg-primitives/std", "cfg-types/std", "cfg-traits/std", "cfg-utils/std", @@ -66,22 +47,11 @@ std = [ "frame-system/std", "sp-std/std", "sp-runtime/std", - "orml-tokens/std", "orml-traits/std", - "pallet-balances/std", "staging-xcm/std", - "pallet-ethereum/std", - "xcm-primitives/std", - "ethabi/std", - "pallet-uniques/std", - "cfg-primitives/std", - "frame-benchmarking/std", "scale-info/std", - "fp-self-contained/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", "orml-tokens/runtime-benchmarks", "cfg-primitives/runtime-benchmarks", "cfg-traits/runtime-benchmarks", @@ -89,9 +59,8 @@ runtime-benchmarks = [ "cfg-utils/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-ethereum/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "xcm-primitives/runtime-benchmarks", + "cfg-mocks/runtime-benchmarks", ] try-runtime = [ "cfg-primitives/try-runtime", @@ -101,8 +70,6 @@ try-runtime = [ "cfg-types/try-runtime", "cfg-utils/try-runtime", "frame-system/try-runtime", - "pallet-ethereum/try-runtime", - "pallet-balances/try-runtime", - "fp-self-contained/try-runtime", "sp-runtime/try-runtime", + "cfg-mocks/try-runtime", ] diff --git a/pallets/liquidity-pools/src/contract.rs b/pallets/liquidity-pools/src/contract.rs deleted file mode 100644 index 852b6e1fc8..0000000000 --- a/pallets/liquidity-pools/src/contract.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2021 Centrifuge Foundation (centrifuge.io). -// This file is part of Centrifuge chain project. - -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). - -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -use ethabi::{Bytes, Contract}; -use sp_std::{vec, vec::Vec}; - -/// The solidity LiquidityPools' XCMRouter handle function name. -static HANDLE_FUNCTION: &str = "handle"; - -/// Return the encoded contract call, i.e, -/// LiquidityPoolsXcmRouter::handle(encoded_msg). -pub fn encoded_contract_call(encoded_msg: Vec) -> Bytes { - let contract = xcm_router_contract(); - let encoded_contract_call = contract - .function(HANDLE_FUNCTION) - .expect("Known at compilation time") - .encode_input(&[ethabi::Token::Bytes(encoded_msg)]) - .expect("Known at compilation time"); - - encoded_contract_call -} - -/// The LiquidityPoolsXcmRouter Abi as in ethabi::Contract. -/// Note: We only concern ourselves with the `handle` function of the contract -/// since that's all we need to build the calls for remote EVM execution. -pub fn xcm_router_contract() -> Contract { - use sp_std::collections::btree_map::BTreeMap; - - let mut functions = BTreeMap::new(); - #[allow(deprecated)] - functions.insert( - "handle".into(), - vec![ethabi::Function { - name: HANDLE_FUNCTION.into(), - inputs: vec![ethabi::Param { - name: "message".into(), - kind: ethabi::ParamType::Bytes, - internal_type: None, - }], - outputs: vec![], - constant: Some(false), - state_mutability: Default::default(), - }], - ); - - ethabi::Contract { - constructor: None, - functions, - events: Default::default(), - errors: Default::default(), - receive: false, - fallback: false, - } -} diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index fcf43a495c..50421af6ce 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -15,7 +15,7 @@ use cfg_traits::{ investments::TrancheCurrency, liquidity_pools::OutboundQueue, StatusNotificationHook, }; use cfg_types::{ - domain_address::{Domain, DomainAddress}, + domain_address::DomainAddress, investments::{ExecutedForeignCollect, ExecutedForeignDecreaseInvest}, }; use frame_support::{ @@ -26,7 +26,7 @@ use frame_support::{ transactional, }; use sp_core::Get; -use sp_runtime::{traits::Convert, DispatchError, DispatchResult}; +use sp_runtime::{DispatchError, DispatchResult}; use sp_std::marker::PhantomData; use crate::{pallet::Config, Message, MessageOf, Pallet}; @@ -141,7 +141,7 @@ where T::Tokens::transfer( investment_id.clone().into(), &investor, - &Domain::convert(domain_address.domain()), + &domain_address.domain().into_account(), status.amount_tranche_tokens_payout, Preservation::Expendable, )?; diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 3386fddff4..185d04cbd4 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -81,7 +81,7 @@ where T::Tokens::transfer( invest_id.into(), - &Domain::convert(sending_domain), + &sending_domain.into_account(), &local_representation_of_receiver, amount, Preservation::Expendable, @@ -206,7 +206,7 @@ where // origination domain T::Tokens::transfer( invest_id.clone().into(), - &Domain::convert(sending_domain.domain()), + &sending_domain.domain().into_account(), &investor, amount, Preservation::Expendable, @@ -252,7 +252,7 @@ where T::Tokens::transfer( invest_id.clone().into(), &investor, - &Domain::convert(destination.domain()), + &destination.domain().into_account(), tranche_tokens_payout, Preservation::Expendable, )?; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 2d1a0dea54..76d8c827b6 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -41,7 +41,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use core::convert::TryFrom; -use cfg_traits::liquidity_pools::{InboundQueue, OutboundQueue}; +use cfg_traits::{ + liquidity_pools::{InboundQueue, OutboundQueue}, + PreConditions, +}; use cfg_types::{ domain_address::{Domain, DomainAddress}, tokens::GeneralCurrencyIndex, @@ -56,8 +59,6 @@ use frame_support::{ }; use orml_traits::asset_registry::{self, Inspect as _}; pub use pallet::*; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert}, FixedPointNumber, SaturatedConversion, @@ -73,25 +74,16 @@ use staging_xcm::{ pub mod defensive_weights; mod message; -pub use message::*; - -mod routers; -pub use routers::*; - -mod contract; -pub use contract::*; +pub use message::Message; pub mod hooks; mod inbound; -/// The Parachains that Centrifuge Liquidity Pools support. -#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum ParachainId { - /// Moonbeam - It may be Moonbeam on Polkadot, Moonriver on Kusama, or - /// Moonbase on a testnet. - Moonbeam, -} +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; // Type aliases pub type MessageOf = Message< @@ -102,8 +94,6 @@ pub type MessageOf = Message< ::BalanceRatio, >; -pub type CurrencyIdOf = ::CurrencyId; - pub type GeneralCurrencyIndexType = u128; pub type GeneralCurrencyIndexOf = @@ -113,8 +103,7 @@ pub type GeneralCurrencyIndexOf = pub mod pallet { use cfg_traits::{ investments::{ForeignInvestment, TrancheCurrency}, - CurrencyInspect, Permissions, PoolInspect, PreConditions, Seconds, TimeAsSecs, - TrancheTokenPrice, + CurrencyInspect, Permissions, PoolInspect, Seconds, TimeAsSecs, TrancheTokenPrice, }; use cfg_types::{ permissions::{PermissionScope, PoolRole, Role}, @@ -172,23 +161,19 @@ pub mod pallet { + FixedPointNumber + TypeInfo; - /// The origin allowed to make admin-like changes, such calling - /// `set_domain_router`. - type AdminOrigin: EnsureOrigin; - /// The source of truth for pool inspection operations such as its /// existence, the corresponding tranche token or the investment /// currency. type PoolInspect: PoolInspect< Self::AccountId, - CurrencyIdOf, + Self::CurrencyId, PoolId = Self::PoolId, TrancheId = Self::TrancheId, >; type TrancheTokenPrice: TrancheTokenPrice< Self::AccountId, - CurrencyIdOf, + Self::CurrencyId, BalanceRatio = Self::BalanceRatio, PoolId = Self::PoolId, TrancheId = Self::TrancheId, @@ -198,7 +183,7 @@ pub mod pallet { /// The source of truth for investment permissions. type Permission: Permissions< Self::AccountId, - Scope = PermissionScope>, + Scope = PermissionScope, Role = Role, Error = DispatchError, >; @@ -210,15 +195,11 @@ pub mod pallet { /// The type for handling transfers, burning and minting of /// multi-assets. type Tokens: Mutate - + Inspect< - Self::AccountId, - AssetId = CurrencyIdOf, - Balance = ::Balance, - >; + + Inspect; /// The currency type of investments. type TrancheCurrency: TrancheCurrency - + Into> + + Into + Clone; /// Enables investing and redeeming into investment classes with foreign @@ -227,7 +208,7 @@ pub mod pallet { Self::AccountId, Amount = Self::Balance, TrancheAmount = Self::Balance, - CurrencyId = CurrencyIdOf, + CurrencyId = Self::CurrencyId, Error = DispatchError, InvestmentId = ::TrancheCurrency, >; @@ -235,7 +216,7 @@ pub mod pallet { /// The source of truth for the transferability of assets via the /// LiquidityPools feature. type AssetRegistry: asset_registry::Inspect< - AssetId = CurrencyIdOf, + AssetId = Self::CurrencyId, Balance = ::Balance, CustomMetadata = CustomMetadata, >; @@ -251,15 +232,11 @@ pub mod pallet { + TryInto, Error = DispatchError> + TryFrom, Error = DispatchError> // Enables checking whether currency is tranche token - + CurrencyInspect>; + + CurrencyInspect; /// The converter from a DomainAddress to a Substrate AccountId. type DomainAddressToAccountId: Convert; - /// The converter from a Domain and 32 byte array to Substrate - /// AccountId. - type DomainAccountToAccountId: Convert<(Domain, [u8; 32]), Self::AccountId>; - /// The converter from a Domain and a 32 byte array to DomainAddress. type DomainAccountToDomainAddress: Convert<(Domain, [u8; 32]), DomainAddress>; @@ -274,13 +251,13 @@ pub mod pallet { #[pallet::constant] type GeneralCurrencyPrefix: Get<[u8; 12]>; - #[pallet::constant] /// The type for paying the transaction fees for the dispatch of /// `Executed*` and `ScheduleUpgrade` messages. /// /// NOTE: We need to make sure to collect the appropriate amount /// beforehand as part of receiving the corresponding investment /// message. + #[pallet::constant] type TreasuryAccount: Get; type PreTransferFilter: PreConditions< @@ -355,7 +332,7 @@ pub mod pallet { ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { /// Add a pool to a given domain - #[pallet::weight(< T as Config >::WeightInfo::add_pool())] + #[pallet::weight(T::WeightInfo::add_pool())] #[pallet::call_index(2)] pub fn add_pool( origin: OriginFor, @@ -383,7 +360,7 @@ pub mod pallet { } /// Add a tranche to a given domain - #[pallet::weight(< T as Config >::WeightInfo::add_tranche())] + #[pallet::weight(T::WeightInfo::add_tranche())] #[pallet::call_index(3)] pub fn add_tranche( origin: OriginFor, @@ -393,11 +370,6 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin.clone())?; - ensure!( - T::PoolInspect::tranche_exists(pool_id, tranche_id), - Error::::TrancheNotFound - ); - ensure!( T::Permission::has( PermissionScope::Pool(pool_id), @@ -440,13 +412,13 @@ pub mod pallet { /// domain, this call origin can be permissionless. /// /// The `currency_id` parameter is necessary for the EVM side. - #[pallet::weight(< T as Config >::WeightInfo::update_token_price())] + #[pallet::weight(T::WeightInfo::update_token_price())] #[pallet::call_index(4)] pub fn update_token_price( origin: OriginFor, pool_id: T::PoolId, tranche_id: T::TrancheId, - currency_id: CurrencyIdOf, + currency_id: T::CurrencyId, destination: Domain, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; @@ -484,7 +456,7 @@ pub mod pallet { } /// Update a member - #[pallet::weight(< T as Config >::WeightInfo::update_member())] + #[pallet::weight(T::WeightInfo::update_member())] #[pallet::call_index(5)] pub fn update_member( origin: OriginFor, @@ -539,14 +511,14 @@ pub mod pallet { /// /// NOTE: The transferring account is not kept alive as we allow its /// death. - #[pallet::weight(< T as Config >::WeightInfo::transfer())] + #[pallet::weight(T::WeightInfo::transfer())] #[pallet::call_index(6)] pub fn transfer_tranche_tokens( origin: OriginFor, pool_id: T::PoolId, tranche_id: T::TrancheId, domain_address: DomainAddress, - amount: ::Balance, + amount: T::Balance, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; @@ -573,7 +545,7 @@ pub mod pallet { T::Tokens::transfer( invest_id.into(), &who, - &Domain::convert(domain_address.domain()), + &domain_address.domain().into_account(), amount, // NOTE: Here, we allow death Preservation::Expendable, @@ -587,10 +559,7 @@ pub mod pallet { tranche_id, amount, domain: domain_address.domain(), - sender: who - .encode() - .try_into() - .map_err(|_| DispatchError::Other("Conversion to 32 bytes failed"))?, + sender: who.into(), receiver: domain_address.address(), }, )?; @@ -604,19 +573,19 @@ pub mod pallet { /// /// NOTE: The transferring account is not kept alive as we allow its /// death. - #[pallet::weight(< T as Config >::WeightInfo::transfer())] + #[pallet::weight(T::WeightInfo::transfer())] #[pallet::call_index(7)] pub fn transfer( origin: OriginFor, - currency_id: CurrencyIdOf, + currency_id: T::CurrencyId, receiver: DomainAddress, - amount: ::Balance, + amount: T::Balance, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; ensure!(!amount.is_zero(), Error::::InvalidTransferAmount); ensure!( - !CurrencyIdOf::::is_tranche_token(currency_id), + !T::CurrencyId::is_tranche_token(currency_id), Error::::InvalidTransferCurrency ); let currency = Self::try_get_general_index(currency_id)?; @@ -665,10 +634,7 @@ pub mod pallet { Message::Transfer { amount, currency, - sender: who - .encode() - .try_into() - .map_err(|_| DispatchError::Other("Conversion to 32 bytes failed"))?, + sender: who.into(), receiver: receiver.address(), }, )?; @@ -680,7 +646,7 @@ pub mod pallet { /// from the given currency. #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] #[pallet::call_index(8)] - pub fn add_currency(origin: OriginFor, currency_id: CurrencyIdOf) -> DispatchResult { + pub fn add_currency(origin: OriginFor, currency_id: T::CurrencyId) -> DispatchResult { let who = ensure_signed(origin)?; let currency = Self::try_get_general_index(currency_id)?; @@ -709,7 +675,7 @@ pub mod pallet { pub fn allow_investment_currency( origin: OriginFor, pool_id: T::PoolId, - currency_id: CurrencyIdOf, + currency_id: T::CurrencyId, ) -> DispatchResult { // TODO(future): In the future, should be permissioned by trait which // does not exist yet. @@ -754,7 +720,7 @@ pub mod pallet { } /// Schedule an upgrade of an EVM-based liquidity pool contract instance - #[pallet::weight(::WeightInfo::cancel_upgrade())] + #[pallet::weight(T::WeightInfo::cancel_upgrade())] #[pallet::call_index(11)] pub fn cancel_upgrade( origin: OriginFor, @@ -775,7 +741,7 @@ pub mod pallet { /// NOTE: Pulls the metadata from the `AssetRegistry` and thus requires /// the pool admin to have updated the tranche tokens metadata there /// beforehand. - #[pallet::weight(::WeightInfo::update_tranche_token_metadata())] + #[pallet::weight(T::WeightInfo::update_tranche_token_metadata())] #[pallet::call_index(12)] pub fn update_tranche_token_metadata( origin: OriginFor, @@ -815,7 +781,7 @@ pub mod pallet { pub fn disallow_investment_currency( origin: OriginFor, pool_id: T::PoolId, - currency_id: CurrencyIdOf, + currency_id: T::CurrencyId, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -848,13 +814,13 @@ pub mod pallet { /// Requires the currency to be registered in the `AssetRegistry`. /// /// NOTE: Reverse operation of `try_get_currency_id`. - pub fn try_get_general_index(currency: CurrencyIdOf) -> Result { + pub fn try_get_general_index(currency: T::CurrencyId) -> Result { ensure!( T::AssetRegistry::metadata(¤cy).is_some(), Error::::AssetNotFound ); - let general_index: GeneralCurrencyIndexOf = CurrencyIdOf::::try_into(currency)?; + let general_index: GeneralCurrencyIndexOf = T::CurrencyId::try_into(currency)?; Ok(general_index.index) } @@ -866,8 +832,8 @@ pub mod pallet { /// NOTE: Reverse operation of `try_get_general_index`. pub fn try_get_currency_id( index: GeneralCurrencyIndexOf, - ) -> Result, DispatchError> { - let currency = CurrencyIdOf::::try_from(index)?; + ) -> Result { + let currency = T::CurrencyId::try_from(index)?; ensure!( T::AssetRegistry::metadata(¤cy).is_some(), Error::::AssetNotFound @@ -882,7 +848,7 @@ pub mod pallet { /// /// Requires the currency to be registered in the `AssetRegistry`. pub fn try_get_wrapped_token( - currency_id: &CurrencyIdOf, + currency_id: &T::CurrencyId, ) -> Result { let meta = T::AssetRegistry::metadata(currency_id).ok_or(Error::::AssetNotFound)?; ensure!( @@ -937,7 +903,7 @@ pub mod pallet { /// Performs multiple checks for the provided currency and returns its /// general index and the EVM chain ID associated with it. pub fn validate_investment_currency( - currency_id: CurrencyIdOf, + currency_id: T::CurrencyId, ) -> Result<(u128, EVMChainId), DispatchError> { // Ensure the currency is enabled as pool_currency let metadata = @@ -954,6 +920,11 @@ pub mod pallet { Ok((currency, chain_id)) } + + fn domain_account_to_account_id(domain_account: (Domain, [u8; 32])) -> T::AccountId { + let domain_address = T::DomainAccountToDomainAddress::convert(domain_account); + T::DomainAddressToAccountId::convert(domain_address) + } } impl InboundQueue for Pallet @@ -1000,7 +971,7 @@ pub mod pallet { } => Self::handle_increase_invest_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), amount, ), @@ -1013,7 +984,7 @@ pub mod pallet { } => Self::handle_decrease_invest_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), amount, ), @@ -1026,7 +997,7 @@ pub mod pallet { } => Self::handle_increase_redeem_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), amount, currency.into(), sender, @@ -1040,7 +1011,7 @@ pub mod pallet { } => Self::handle_decrease_redeem_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), amount, currency.into(), sender, @@ -1053,7 +1024,7 @@ pub mod pallet { } => Self::handle_collect_investment( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), ), Message::CollectRedeem { @@ -1064,7 +1035,7 @@ pub mod pallet { } => Self::handle_collect_redemption( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), ), Message::CancelInvestOrder { @@ -1075,7 +1046,7 @@ pub mod pallet { } => Self::handle_cancel_invest_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), ), Message::CancelRedeemOrder { @@ -1086,7 +1057,7 @@ pub mod pallet { } => Self::handle_cancel_redeem_order( pool_id, tranche_id, - T::DomainAccountToAccountId::convert((sender.domain(), investor)), + Self::domain_account_to_account_id((sender.domain(), investor)), currency.into(), sender, ), @@ -1097,25 +1068,3 @@ pub mod pallet { } } } - -#[cfg(test)] -mod tests { - use parity_scale_codec::{Decode, Encode}; - - use crate::Domain; - - #[test] - fn test_domain_encode_decode() { - test_domain_identity(Domain::Centrifuge); - test_domain_identity(Domain::EVM(1284)); - test_domain_identity(Domain::EVM(1)); - } - - /// Test that decode . encode results in the original value - fn test_domain_identity(domain: Domain) { - let encoded = domain.encode(); - let decoded: Domain = Domain::decode(&mut encoded.as_slice()).expect(""); - - assert_eq!(domain, decoded); - } -} diff --git a/pallets/liquidity-pools/src/mock.rs b/pallets/liquidity-pools/src/mock.rs new file mode 100644 index 0000000000..aaff960192 --- /dev/null +++ b/pallets/liquidity-pools/src/mock.rs @@ -0,0 +1,141 @@ +use cfg_primitives::{PoolId, TrancheId}; +use cfg_traits::Millis; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + permissions::PermissionScope, + tokens::{AssetStringLimit, CurrencyId, CustomMetadata, TrancheCurrency}, +}; +use frame_support::derive_impl; +use orml_traits::parameter_type_with_key; +use sp_runtime::{traits::IdentityLookup, AccountId32, DispatchResult, FixedU64}; + +use crate::pallet as pallet_liquidity_pools; + +pub type Balance = u128; +pub type AccountId = AccountId32; +pub type Ratio = FixedU64; + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + Time: cfg_mocks::time::pallet, + Permissions: cfg_mocks::permissions::pallet, + Pools: cfg_mocks::pools::pallet, + AssetRegistry: cfg_mocks::asset_registry::pallet, + ForeignInvestment: cfg_mocks::foreign_investment::pallet, + Gateway: cfg_mocks::outbound_queue::pallet, + DomainAddressToAccountId: cfg_mocks::converter::pallet::, + DomainAccountToDomainAddress: cfg_mocks::converter::pallet::, + TransferFilter: cfg_mocks::pre_conditions::pallet, + Tokens: orml_tokens, + LiquidityPools: pallet_liquidity_pools, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Block = frame_system::mocking::MockBlock; + type Lookup = IdentityLookup; +} + +impl cfg_mocks::time::pallet::Config for Runtime { + type Moment = Millis; +} + +impl cfg_mocks::permissions::pallet::Config for Runtime { + type Scope = PermissionScope; +} + +impl cfg_mocks::pools::pallet::Config for Runtime { + type Balance = Balance; + type BalanceRatio = Ratio; + type CurrencyId = CurrencyId; + type PoolId = PoolId; + type TrancheCurrency = TrancheCurrency; + type TrancheId = TrancheId; +} + +impl cfg_mocks::asset_registry::pallet::Config for Runtime { + type AssetId = CurrencyId; + type Balance = Balance; + type CustomMetadata = CustomMetadata; + type StringLimit = AssetStringLimit; +} + +impl cfg_mocks::foreign_investment::pallet::Config for Runtime { + type Amount = Balance; + type CurrencyId = CurrencyId; + type InvestmentId = TrancheCurrency; + type TrancheAmount = Balance; +} + +impl cfg_mocks::outbound_queue::pallet::Config for Runtime { + type Destination = Domain; + type Message = crate::MessageOf; + type Sender = AccountId; +} + +impl cfg_mocks::converter::pallet::Config for Runtime { + type From = DomainAddress; + type To = AccountId; +} + +impl cfg_mocks::converter::pallet::Config for Runtime { + type From = (Domain, [u8; 32]); + type To = DomainAddress; +} + +impl cfg_mocks::pre_conditions::pallet::Config for Runtime { + type Conditions = (AccountId, DomainAddress, CurrencyId); + type Result = DispatchResult; +} + +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Default::default() + }; +} + +impl orml_tokens::Config for Runtime { + type Amount = i64; + type Balance = Balance; + type CurrencyHooks = (); + type CurrencyId = CurrencyId; + type DustRemovalWhitelist = frame_support::traits::Nothing; + type ExistentialDeposits = ExistentialDeposits; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +frame_support::parameter_types! { + pub CurrencyPrefix: [u8; 12] = [1; 12]; + pub TreasuryAccount: AccountId = [2; 32].into(); +} + +impl pallet_liquidity_pools::Config for Runtime { + type AssetRegistry = AssetRegistry; + type Balance = Balance; + type BalanceRatio = Ratio; + type CurrencyId = CurrencyId; + type DomainAccountToDomainAddress = DomainAccountToDomainAddress; + type DomainAddressToAccountId = DomainAddressToAccountId; + type ForeignInvestment = ForeignInvestment; + type GeneralCurrencyPrefix = CurrencyPrefix; + type OutboundQueue = Gateway; + type Permission = Permissions; + type PoolId = PoolId; + type PoolInspect = Pools; + type PreTransferFilter = TransferFilter; + type RuntimeEvent = RuntimeEvent; + type Time = Time; + type Tokens = Tokens; + type TrancheCurrency = TrancheCurrency; + type TrancheId = TrancheId; + type TrancheTokenPrice = Pools; + type TreasuryAccount = TreasuryAccount; + type WeightInfo = (); +} diff --git a/pallets/liquidity-pools/src/routers.rs b/pallets/liquidity-pools/src/routers.rs deleted file mode 100644 index 15d16e4dec..0000000000 --- a/pallets/liquidity-pools/src/routers.rs +++ /dev/null @@ -1,35 +0,0 @@ -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_core::H160; -use sp_runtime::{traits::ConstU32, BoundedVec}; -use sp_std::boxed::Box; -use staging_xcm::VersionedLocation; - -#[allow(clippy::derive_partial_eq_without_eq)] // XcmDomain does not impl Eq -#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum Router { - // An XCM-based router - Xcm(XcmDomain), -} - -/// XcmDomain gathers all the required fields to build and send remote -/// calls to a specific XCM-based Domain. -#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct XcmDomain { - /// the xcm multilocation of the domain - pub location: Box, - /// The ethereum_xcm::Call::transact call index on a given domain. - /// It should contain the pallet index + the `transact` call index, to which - /// we will append the eth_tx param. You can obtain this value by building - /// an ethereum_xcm::transact call with Polkadot JS on the target chain. - pub ethereum_xcm_transact_call_index: - BoundedVec>, - /// The LiquidityPoolsXcmRouter contract address on a given domain - pub contract_address: H160, - /// The currency in which execution fees will be paid on - pub fee_currency: CurrencyId, - /// The max gas_limit we want to propose for a remote evm execution - pub max_gas_limit: u64, -} diff --git a/pallets/liquidity-pools/src/tests.rs b/pallets/liquidity-pools/src/tests.rs new file mode 100644 index 0000000000..439fe35362 --- /dev/null +++ b/pallets/liquidity-pools/src/tests.rs @@ -0,0 +1,632 @@ +use cfg_primitives::{PoolId, TrancheId}; +use cfg_traits::{liquidity_pools::InboundQueue, Millis}; +use cfg_types::{ + domain_address::DomainAddress, + permissions::{PermissionScope, PoolRole, Role}, + tokens::{AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata}, +}; +use cfg_utils::vec_to_fixed_array; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + fungibles::{Inspect as _, Mutate as _}, + PalletInfo as _, + }, +}; +use sp_runtime::{DispatchError, TokenError}; +use staging_xcm::{ + v4::{Junction::*, Location, NetworkId}, + VersionedLocation, +}; + +use crate::{mock::*, Error, GeneralCurrencyIndexOf, Message}; + +const CHAIN_ID: u64 = 1; +const ALICE: AccountId = AccountId::new([0; 32]); +const CONTRACT_ACCOUNT: [u8; 20] = [1; 20]; +const CONTRACT_ACCOUNT_ID: AccountId = AccountId::new([1; 32]); +const EVM_ADDRESS: DomainAddress = DomainAddress::EVM(CHAIN_ID, CONTRACT_ACCOUNT); +const AMOUNT: Balance = 100; +const CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); +const POOL_ID: PoolId = 1; +const TRANCHE_ID: TrancheId = [1; 16]; +const NOW: Millis = 0; +const NAME: &[u8] = b"Token name"; +const SYMBOL: &[u8] = b"Token symbol"; +const DECIMALS: u8 = 6; +const TRANCHE_CURRENCY: CurrencyId = CurrencyId::Tranche(POOL_ID, TRANCHE_ID); + +mod util { + use super::*; + + pub fn default_metadata() -> AssetMetadata { + AssetMetadata { + decimals: DECIMALS as u32, + name: Vec::from(NAME).try_into().unwrap(), + symbol: Vec::from(SYMBOL).try_into().unwrap(), + ..cfg_types::tokens::default_metadata() + } + } + + pub fn transferable_metadata() -> AssetMetadata { + AssetMetadata { + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + ..Default::default() + }, + ..default_metadata() + } + } + + pub fn wrapped_transferable_metadata() -> AssetMetadata { + let pallet_index = PalletInfo::index::(); + AssetMetadata { + 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, + }, + ], + ))), + ..transferable_metadata() + } + } + + pub fn currency_index(currency_id: CurrencyId) -> u128 { + GeneralCurrencyIndexOf::::try_from(currency_id) + .unwrap() + .index + } +} + +mod transfer { + use super::*; + + #[test] + fn success() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::wrapped_transferable_metadata())); + TransferFilter::mock_check(|_| Ok(())); + Tokens::mint_into(CURRENCY_ID, &ALICE, AMOUNT).unwrap(); + Gateway::mock_submit(|sender, destination, msg| { + assert_eq!(sender, ALICE); + assert_eq!(destination, EVM_ADDRESS.domain()); + assert_eq!( + msg, + Message::Transfer { + currency: util::currency_index(CURRENCY_ID), + sender: ALICE.into(), + receiver: EVM_ADDRESS.address(), + amount: AMOUNT + } + ); + Ok(()) + }); + + assert_ok!(LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CurrencyId::ForeignAsset(1), + EVM_ADDRESS, + AMOUNT + )); + + assert_eq!(Tokens::total_issuance(CURRENCY_ID), 0); + }) + } + + mod erroring_out_when { + use super::*; + + #[test] + fn with_zero_balance() { + System::externalities().execute_with(|| { + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + 0 + ), + Error::::InvalidTransferAmount, + ); + }) + } + + #[test] + fn with_tranche_currency() { + System::externalities().execute_with(|| { + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CurrencyId::Tranche(42, [0; 16]), + EVM_ADDRESS, + AMOUNT + ), + Error::::InvalidTransferCurrency, + ); + }) + } + + #[test] + fn with_no_metadata() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| None); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::AssetNotFound, + ); + }) + } + + #[test] + fn with_unsupported_token() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::default_metadata())); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CurrencyId::Native, + EVM_ADDRESS, + AMOUNT + ), + TokenError::Unsupported, + ); + }) + } + + #[test] + fn with_no_transferible_asset() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::default_metadata())); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::AssetNotLiquidityPoolsTransferable, + ); + }) + } + + #[test] + fn with_wrong_location() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::transferable_metadata())); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::AssetNotLiquidityPoolsWrappedToken + ); + }) + } + + #[test] + fn with_wrong_domain() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::wrapped_transferable_metadata())); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + DomainAddress::Centrifuge([2; 32]), + AMOUNT + ), + Error::::InvalidDomain + ); + }) + } + + #[test] + fn without_satisfy_filter() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::wrapped_transferable_metadata())); + TransferFilter::mock_check(|_| Err(DispatchError::Other("Err"))); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + AMOUNT + ), + DispatchError::Other("Err"), + ); + }) + } + + #[test] + fn without_sufficient_balance() { + System::externalities().execute_with(|| { + AssetRegistry::mock_metadata(|_| Some(util::wrapped_transferable_metadata())); + TransferFilter::mock_check(|_| Ok(())); + + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(ALICE), + CURRENCY_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::BalanceTooLow + ); + }) + } + } +} + +mod transfer_tranche_tokens { + use super::*; + + #[test] + fn success() { + System::externalities().execute_with(|| { + DomainAddressToAccountId::mock_convert(|_| CONTRACT_ACCOUNT_ID); + Time::mock_now(|| NOW); + Permissions::mock_has(move |scope, who, role| { + assert_eq!(who, CONTRACT_ACCOUNT_ID); + assert!(matches!(scope, PermissionScope::Pool(POOL_ID))); + assert!(matches!( + role, + Role::PoolRole(PoolRole::TrancheInvestor(TRANCHE_ID, NOW)) + )); + true + }); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| true); + TransferFilter::mock_check(|_| Ok(())); + Tokens::mint_into(TRANCHE_CURRENCY, &ALICE, AMOUNT).unwrap(); + Gateway::mock_submit(|sender, destination, msg| { + assert_eq!(sender, ALICE); + assert_eq!(destination, EVM_ADDRESS.domain()); + assert_eq!( + msg, + Message::TransferTrancheTokens { + pool_id: POOL_ID, + tranche_id: TRANCHE_ID, + sender: ALICE.into(), + domain: EVM_ADDRESS.domain(), + receiver: EVM_ADDRESS.address(), + amount: AMOUNT + } + ); + Ok(()) + }); + + assert_ok!(LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + AMOUNT + )); + + let destination = EVM_ADDRESS.domain().into_account(); + assert_eq!(Tokens::balance(TRANCHE_CURRENCY, &ALICE), 0); + assert_eq!(Tokens::balance(TRANCHE_CURRENCY, &destination), AMOUNT); + }) + } + + mod erroring_out_when { + use super::*; + + #[test] + fn with_zero_balance() { + System::externalities().execute_with(|| { + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + 0 + ), + Error::::InvalidTransferAmount, + ); + }) + } + + #[test] + fn with_wrong_permissions() { + System::externalities().execute_with(|| { + DomainAddressToAccountId::mock_convert(|_| CONTRACT_ACCOUNT_ID); + Time::mock_now(|| NOW); + Permissions::mock_has(|_, _, _| false); + + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::UnauthorizedTransfer, + ); + }) + } + + #[test] + fn with_wrong_pool() { + System::externalities().execute_with(|| { + DomainAddressToAccountId::mock_convert(|_| CONTRACT_ACCOUNT_ID); + Time::mock_now(|| NOW); + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| false); + + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::PoolNotFound, + ); + }) + } + + #[test] + fn with_wrong_tranche() { + System::externalities().execute_with(|| { + DomainAddressToAccountId::mock_convert(|_| CONTRACT_ACCOUNT_ID); + Time::mock_now(|| NOW); + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| false); + + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + AMOUNT + ), + Error::::TrancheNotFound, + ); + }) + } + + #[test] + fn without_satisfy_filter() { + System::externalities().execute_with(|| { + DomainAddressToAccountId::mock_convert(|_| CONTRACT_ACCOUNT_ID); + Time::mock_now(|| NOW); + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| true); + TransferFilter::mock_check(|_| Err(DispatchError::Other("Err"))); + + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS, + AMOUNT + ), + DispatchError::Other("Err"), + ); + }) + } + } +} + +mod add_pool { + use super::*; + + #[test] + fn success() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |scope, who, role| { + assert_eq!(who, ALICE); + assert!(matches!(scope, PermissionScope::Pool(POOL_ID))); + assert!(matches!(role, Role::PoolRole(PoolRole::PoolAdmin))); + true + }); + Pools::mock_pool_exists(|_| true); + Gateway::mock_submit(|sender, destination, msg| { + assert_eq!(sender, ALICE); + assert_eq!(destination, EVM_ADDRESS.domain()); + assert_eq!(msg, Message::AddPool { pool_id: POOL_ID }); + Ok(()) + }); + + assert_ok!(LiquidityPools::add_pool( + RuntimeOrigin::signed(ALICE), + POOL_ID, + EVM_ADDRESS.domain(), + )); + }) + } + + mod erroring_out_when { + use super::*; + + #[test] + fn with_wrong_pool() { + System::externalities().execute_with(|| { + Pools::mock_pool_exists(|_| false); + + assert_noop!( + LiquidityPools::add_pool( + RuntimeOrigin::signed(ALICE), + POOL_ID, + EVM_ADDRESS.domain(), + ), + Error::::PoolNotFound + ); + }) + } + + #[test] + fn with_wrong_permissions() { + System::externalities().execute_with(|| { + Pools::mock_pool_exists(|_| true); + Permissions::mock_has(move |_, _, _| false); + + assert_noop!( + LiquidityPools::add_pool( + RuntimeOrigin::signed(ALICE), + POOL_ID, + EVM_ADDRESS.domain(), + ), + Error::::NotPoolAdmin + ); + }) + } + } +} + +mod add_tranche { + use super::*; + + #[test] + fn success() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |scope, who, role| { + assert_eq!(who, ALICE); + assert!(matches!(scope, PermissionScope::Pool(POOL_ID))); + assert!(matches!(role, Role::PoolRole(PoolRole::PoolAdmin))); + true + }); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| true); + AssetRegistry::mock_metadata(|_| Some(util::default_metadata())); + Gateway::mock_submit(|sender, destination, msg| { + assert_eq!(sender, ALICE); + assert_eq!(destination, EVM_ADDRESS.domain()); + assert_eq!( + msg, + Message::AddTranche { + pool_id: POOL_ID, + tranche_id: TRANCHE_ID, + token_name: vec_to_fixed_array(NAME), + token_symbol: vec_to_fixed_array(SYMBOL), + decimals: DECIMALS, + restriction_set: 1 + } + ); + Ok(()) + }); + + assert_ok!(LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS.domain(), + )); + }) + } + + mod erroring_out_when { + use super::*; + + #[test] + fn with_wrong_permissions() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |_, _, _| false); + + assert_noop!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS.domain(), + ), + Error::::NotPoolAdmin + ); + }) + } + + #[test] + fn with_wrong_pool() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| false); + + assert_noop!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS.domain(), + ), + Error::::PoolNotFound + ); + }) + } + + #[test] + fn with_wrong_tranche() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| false); + + assert_noop!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS.domain(), + ), + Error::::TrancheNotFound, + ); + }) + } + + #[test] + fn with_no_metadata() { + System::externalities().execute_with(|| { + Permissions::mock_has(move |_, _, _| true); + Pools::mock_pool_exists(|_| true); + Pools::mock_tranche_exists(|_, _| true); + AssetRegistry::mock_metadata(|_| None); + + assert_noop!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE), + POOL_ID, + TRANCHE_ID, + EVM_ADDRESS.domain(), + ), + Error::::TrancheMetadataNotFound, + ); + }) + } + } +} + +#[test] +fn receiving_output_message() { + System::externalities().execute_with(|| { + let msg = Message::AddPool { pool_id: 123 }; + + assert_noop!( + LiquidityPools::submit(EVM_ADDRESS, msg), + Error::::InvalidIncomingMessage, + ); + }) +} diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 64983606ee..47e5215723 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1779,12 +1779,10 @@ parameter_types! { } impl pallet_liquidity_pools::Config for Runtime { - type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type BalanceRatio = Ratio; type CurrencyId = CurrencyId; - type DomainAccountToAccountId = AccountConverter; type DomainAccountToDomainAddress = AccountConverter; type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 0d9855ff58..e4e1da995d 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -1877,12 +1877,10 @@ parameter_types! { } impl pallet_liquidity_pools::Config for Runtime { - type AdminOrigin = EnsureRootOr; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type BalanceRatio = Ratio; type CurrencyId = CurrencyId; - type DomainAccountToAccountId = AccountConverter; type DomainAccountToDomainAddress = AccountConverter; type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; diff --git a/runtime/common/src/account_conversion.rs b/runtime/common/src/account_conversion.rs index 9e896c9db5..ded709ec11 100644 --- a/runtime/common/src/account_conversion.rs +++ b/runtime/common/src/account_conversion.rs @@ -13,7 +13,7 @@ use cfg_primitives::AccountId; use cfg_types::domain_address::{Domain, DomainAddress}; use pallet_evm::AddressMapping; -use sp_core::{crypto::AccountId32, Get, H160}; +use sp_core::{Get, H160}; use sp_runtime::traits::Convert; use staging_xcm::v4::{Junction::AccountKey20, Location, NetworkId::Ethereum}; use staging_xcm_executor::traits::ConvertLocation; @@ -61,10 +61,15 @@ impl AccountConverter { } } - pub fn into_account_id(address: H160) -> AccountId { + pub fn evm_address_to_account(address: H160) -> AccountId { let chain_id = pallet_evm_chain_id::Pallet::::get(); Self::convert_evm_address(chain_id, address.0) } + + pub fn domain_account_to_account(domain: Domain, account_id: AccountId) -> AccountId { + let domain_address = Self::convert((domain, account_id.into())); + Self::convert(domain_address) + } } impl Convert for AccountConverter { @@ -89,20 +94,6 @@ impl Convert<(Domain, [u8; 32]), DomainAddress> for AccountConverter { } } -impl Convert<(Domain, [u8; 32]), AccountId32> for AccountConverter { - fn convert((domain, account): (Domain, [u8; 32])) -> AccountId32 { - match domain { - Domain::Centrifuge => AccountId32::new(account), - // EVM AccountId20 addresses are right-padded to 32 bytes - Domain::EVM(chain_id) => { - let mut bytes20 = [0; 20]; - bytes20.copy_from_slice(&account[..20]); - Self::convert_evm_address(chain_id, bytes20) - } - } - } -} - // A type that use AccountConverter to carry along with it the Runtime type and // offer an `AddressMapping` implementation. // Required by `pallet_evm` @@ -110,7 +101,7 @@ pub struct RuntimeAccountConverter(sp_std::marker::PhantomData); impl AddressMapping for RuntimeAccountConverter { fn into_account_id(address: H160) -> AccountId { - AccountConverter::into_account_id::(address) + AccountConverter::evm_address_to_account::(address) } } diff --git a/runtime/common/src/gateway.rs b/runtime/common/src/gateway.rs index 4129eec96c..5b75077ac7 100644 --- a/runtime/common/src/gateway.rs +++ b/runtime/common/src/gateway.rs @@ -25,5 +25,5 @@ pub fn get_gateway_account>::as_ref(&sender_account)[0..20]); - AccountConverter::into_account_id::(truncated_sender_account) + AccountConverter::evm_address_to_account::(truncated_sender_account) } diff --git a/runtime/common/src/xcm.rs b/runtime/common/src/xcm.rs index dbba874d87..aa82c339de 100644 --- a/runtime/common/src/xcm.rs +++ b/runtime/common/src/xcm.rs @@ -272,10 +272,7 @@ pub type LocationToAccountId = ( #[cfg(test)] mod test { - use cfg_mocks::{ - pallet_mock_liquidity_pools, pallet_mock_routers, pallet_mock_try_convert, MessageMock, - RouterMock, - }; + use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_routers, MessageMock, RouterMock}; use cfg_primitives::OutboundMessageNonce; use frame_support::{assert_ok, derive_impl, traits::EnsureOrigin}; use frame_system::EnsureRoot; @@ -288,18 +285,14 @@ mod test { type AccountId = u64; - pub fn new_test_ext() -> sp_io::TestExternalities { - System::externalities() - } - // For testing the pallet, we construct a mock runtime. frame_support::construct_runtime!( pub enum Runtime { System: frame_system, Gateway: pallet_liquidity_pools_gateway, MockLP: pallet_mock_liquidity_pools, - MockParaAsEvmChain: pallet_mock_try_convert::, - MockOriginRecovery: pallet_mock_try_convert::, + MockParaAsEvmChain: cfg_mocks::converter::pallet::, + MockOriginRecovery: cfg_mocks::converter::pallet::, } ); @@ -308,14 +301,12 @@ mod test { type Block = frame_system::mocking::MockBlock; } - impl pallet_mock_try_convert::Config for Runtime { - type Error = (); + impl cfg_mocks::converter::pallet::Config for Runtime { type From = ParaId; type To = EVMChainId; } - impl pallet_mock_try_convert::Config for Runtime { - type Error = DispatchError; + impl cfg_mocks::converter::pallet::Config for Runtime { type From = (Vec, Vec); type To = DomainAddress; } @@ -348,7 +339,7 @@ mod test { #[test] fn lp_instance_relayer_converts_correctly() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); assert_ok!(Gateway::add_relayer( @@ -387,7 +378,7 @@ mod test { #[test] fn lp_instance_relayer_fails_with_wrong_location() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); assert_ok!(Gateway::add_relayer( @@ -415,7 +406,7 @@ mod test { #[test] fn lp_instance_relayer_fails_if_relayer_not_set() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { MockParaAsEvmChain::mock_try_convert(|from| { assert_eq!(from, RELAYER_PARA_ID); Ok(RELAYER_EVM_ID) @@ -445,7 +436,7 @@ mod test { #[test] fn lp_instance_relayer_fails_if_para_to_evm_fails() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); assert_ok!(Gateway::add_relayer( @@ -455,7 +446,7 @@ mod test { MockParaAsEvmChain::mock_try_convert(|from| { assert_eq!(from, RELAYER_PARA_ID); - Err(()) + Err(DispatchError::Other("")) }); let location = Location::new( @@ -482,7 +473,7 @@ mod test { #[test] fn lp_instance_relayer_fails_if_wrong_para() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); assert_ok!(Gateway::add_relayer( @@ -492,7 +483,7 @@ mod test { MockParaAsEvmChain::mock_try_convert(|from| { assert_eq!(from, 1); - Err(()) + Err(DispatchError::Other("")) }); let location = Location::new( @@ -519,7 +510,7 @@ mod test { #[test] fn lp_instance_relayer_fails_if_wrong_address() { - new_test_ext().execute_with(|| { + System::externalities().execute_with(|| { let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); assert_ok!(Gateway::add_relayer( diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 00bddcbde6..0e46c15183 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1882,12 +1882,10 @@ parameter_types! { } impl pallet_liquidity_pools::Config for Runtime { - type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type BalanceRatio = Ratio; type CurrencyId = CurrencyId; - type DomainAccountToAccountId = AccountConverter; type DomainAccountToDomainAddress = AccountConverter; type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; diff --git a/runtime/integration-tests/src/generic/cases/assets.rs b/runtime/integration-tests/src/generic/cases/assets.rs index 56cf7e24bd..093cb4f842 100644 --- a/runtime/integration-tests/src/generic/cases/assets.rs +++ b/runtime/integration-tests/src/generic/cases/assets.rs @@ -1,11 +1,9 @@ -use cfg_types::tokens::CurrencyId; +use cfg_types::tokens::{default_metadata, 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, - }, + generic::{config::Runtime, env::Env, envs::runtime_env::RuntimeEnv}, utils::orml_asset_registry, }; diff --git a/runtime/integration-tests/src/generic/cases/currency_conversions.rs b/runtime/integration-tests/src/generic/cases/currency_conversions.rs index a690165203..4cbed8080f 100644 --- a/runtime/integration-tests/src/generic/cases/currency_conversions.rs +++ b/runtime/integration-tests/src/generic/cases/currency_conversions.rs @@ -1,4 +1,4 @@ -use cfg_types::tokens::CurrencyId; +use cfg_types::tokens::{default_metadata, CurrencyId}; use orml_traits::asset_registry::AssetMetadata; use runtime_common::xcm::CurrencyIdConvert; use sp_runtime::traits::Convert; @@ -12,7 +12,7 @@ use crate::generic::{ env::Env, envs::runtime_env::RuntimeEnv, utils::{ - currency::{default_metadata, CurrencyInfo, CustomCurrency}, + currency::{CurrencyInfo, CustomCurrency}, genesis::{self, Genesis}, xcm::transferable_custom, }, diff --git a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs index 19985385f8..b9da600a28 100644 --- a/runtime/integration-tests/src/generic/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/generic/cases/liquidity_pools.rs @@ -3,7 +3,7 @@ use cfg_primitives::{ }; use cfg_traits::{ investments::{Investment, OrderManager, TrancheCurrency}, - liquidity_pools::{Codec, InboundQueue, OutboundQueue}, + liquidity_pools::{InboundQueue, OutboundQueue}, IdentityCurrencyConversion, Permissions, PoolInspect, PoolMutate, Seconds, }; use cfg_types::{ @@ -30,7 +30,7 @@ use liquidity_pools_gateway_routers::{ use orml_traits::MultiCurrency; use pallet_investments::CollectOutcome; use pallet_liquidity_pools::Message; -use pallet_liquidity_pools_gateway::{Call as LiquidityPoolsGatewayCall, GatewayOrigin}; +use pallet_liquidity_pools_gateway::Call as LiquidityPoolsGatewayCall; use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheType}; use polkadot_core_primitives::BlakeTwo256; use runtime_common::{ @@ -52,10 +52,7 @@ use crate::{ config::Runtime, env::{Blocks, Env}, envs::fudge_env::{handle::SIBLING_ID, FudgeEnv, FudgeSupport}, - utils::{ - democracy::execute_via_democracy, genesis, genesis::Genesis, - xcm::enable_para_to_sibling_communication, - }, + utils::{genesis, genesis::Genesis, xcm::enable_para_to_sibling_communication}, }, utils::{accounts::Keyring, orml_asset_registry}, }; @@ -522,7 +519,7 @@ mod utils { // 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()), + &DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(), amount )); @@ -702,128 +699,6 @@ mod add_allow_upgrade { use super::*; - #[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(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - let pool_id = 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 - ); - - // Now create the pool - create_ausd_pool::(pool_id); - - // 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 - ); - - // 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), - )); - }); - } - - #[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(), - ); - - setup_test(&mut env); - - env.parachain_state_mut(|| { - // Now create the pool - let pool_id = POOL_ID; - create_ausd_pool::(pool_id); - - // Verify we can't call pallet_liquidity_pools::Pallet::::add_tranche with a - // non-existing tranche_id - let nonexistent_tranche = [71u8; 16]; - - 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 - ); - - // 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), - )); - - // Edge case: Should throw if tranche exists but metadata does not exist - let tranche_currency_id = CurrencyId::Tranche(pool_id, tranche_id); - - orml_asset_registry::Metadata::::remove(tranche_currency_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 - ); - }); - } - #[test_runtimes([development])] fn update_member() { let mut env = FudgeEnv::::from_parachain_storage( @@ -1670,8 +1545,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -1720,8 +1595,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -1811,8 +1686,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -1911,12 +1786,12 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(); enable_liquidity_pool_transferability::(currency_id); // Create new pool @@ -2058,12 +1933,12 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(); create_currency_pool::(pool_id, currency_id, currency_decimals.into()); do_initial_increase_investment::( pool_id, @@ -2290,8 +2165,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -2313,7 +2188,7 @@ mod foreign_investments { // 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()), + &DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(), amount )); let msg = LiquidityPoolMessage::IncreaseRedeemOrder { @@ -2345,12 +2220,12 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(); // Create new pool create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -2463,12 +2338,12 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = - Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(); // Create new pool create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -2561,8 +2436,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } @@ -2711,8 +2586,8 @@ mod foreign_investments { 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 investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } @@ -2922,8 +2797,10 @@ mod foreign_investments { 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 investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -2968,8 +2845,10 @@ mod foreign_investments { 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 investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -3016,8 +2895,10 @@ mod foreign_investments { 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 investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -3095,8 +2976,10 @@ mod foreign_investments { 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 investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool::(pool_id, currency_id, currency_decimals.into()); @@ -3111,7 +2994,7 @@ mod foreign_investments { // 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()), + &DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(), 1, )); @@ -3184,8 +3067,10 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let pool_currency = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -3260,8 +3145,10 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let pool_currency = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -3277,7 +3164,7 @@ mod foreign_investments { 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()), + &DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(), amount, )); @@ -3340,8 +3227,10 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = AccountConverter::domain_account_to_account( + DOMAIN_MOONBEAM, + Keyring::Bob.id(), + ); let pool_currency = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -3357,7 +3246,7 @@ mod foreign_investments { 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()), + &DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(), amount, )); @@ -3413,14 +3302,14 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); 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()); + DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain().into_account(); let trader: AccountId = Keyring::Alice.into(); create_currency_pool::(pool_id, pool_currency, pool_currency_decimals.into()); @@ -3527,8 +3416,8 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; let pool_currency_decimals = currency_decimals::AUSD; @@ -3666,8 +3555,8 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let trader: AccountId = Keyring::Alice.into(); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -3781,8 +3670,8 @@ mod foreign_investments { env.parachain_state_mut(|| { let pool_id = POOL_ID; - let investor: AccountId = - AccountConverter::convert((DOMAIN_MOONBEAM, Keyring::Bob.into())); + let investor = + AccountConverter::domain_account_to_account(DOMAIN_MOONBEAM, Keyring::Bob.id()); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; let pool_currency_decimals = currency_decimals::AUSD; @@ -3868,118 +3757,6 @@ mod foreign_investments { } } -mod transfers { - use super::*; - - // 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() { - 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 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; - - // 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 - ); - - // 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 - ); - - // 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 - ); - - // Enable LiquidityPools transferability - enable_liquidity_pool_transferability::(currency_id); - - // 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 pre_total_issuance = orml_tokens::Pallet::::total_issuance(currency_id); - - assert_ok!(pallet_liquidity_pools::Pallet::::transfer( - RawOrigin::Signed(source_account.into()).into(), - currency_id, - dest_address.clone(), - amount, - )); - - 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 - ); - }); - } -} - mod routers { use super::*; @@ -4294,189 +4071,3 @@ mod routers { } } } - -mod gateway { - use super::*; - - #[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(), - ); - - let test_domain = Domain::EVM(1); - - 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); - - env.parachain_state_mut(|| { - pallet_evm::AccountCodes::::insert(axelar_contract_address, axelar_contract_code) - }); - - 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), - }, - }; - - 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 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)); - }); - } - - #[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 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() - ) - ); - }); - } - - #[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() - ) - ); - }); - - let msg = LiquidityPoolMessage::AddPool { pool_id: 123 }; - - let encoded_msg = msg.serialize(); - - 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/lp/transfers.rs b/runtime/integration-tests/src/generic/cases/lp/transfers.rs index 864f3f43c0..0aff7d8415 100644 --- a/runtime/integration-tests/src/generic/cases/lp/transfers.rs +++ b/runtime/integration-tests/src/generic/cases/lp/transfers.rs @@ -10,15 +10,13 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{Balance, PoolId}; -use cfg_traits::Seconds; +use cfg_primitives::Balance; use cfg_types::{ domain_address::{Domain, DomainAddress}, - permissions::PoolRole, tokens::CurrencyId, }; use ethabi::{ethereum_types::U256, Token}; -use frame_support::{assert_noop, traits::OriginTrait}; +use frame_support::traits::OriginTrait; use frame_system::pallet_prelude::OriginFor; use pallet_liquidity_pools::Message; use sp_core::ByteArray; @@ -344,48 +342,3 @@ fn transfer_tranche_tokens_domain_to_local() { ); }); } - -#[test_runtimes(all)] -fn transferring_invalid_tranche_tokens_should_fail() { - const INVALID_POOL_ID: PoolId = 100; - const INVALID_TRANCHE_ID: [u8; 16] = [0; 16]; - let mut env = super::setup_full::(); - - env.state_mut(|_| { - crate::generic::utils::pool::give_role::( - lp::utils::remote_account_of::(Keyring::TrancheInvestor(1)), - POOL_A, - PoolRole::TrancheInvestor(INVALID_TRANCHE_ID, Seconds::MAX), - ); - crate::generic::utils::pool::give_role::( - lp::utils::remote_account_of::(Keyring::TrancheInvestor(1)), - INVALID_POOL_ID, - PoolRole::TrancheInvestor(INVALID_TRANCHE_ID, Seconds::MAX), - ); - }); - - let destination = DomainAddress::EVM(EVM_DOMAIN_CHAIN_ID, Keyring::TrancheInvestor(1).into()); - env.state(|_evm| { - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - OriginFor::::signed(Keyring::TrancheInvestor(1).into()), - INVALID_POOL_ID, - INVALID_TRANCHE_ID, - destination.clone(), - AMOUNT - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); - - assert_noop!( - pallet_liquidity_pools::Pallet::::transfer_tranche_tokens( - OriginFor::::signed(Keyring::TrancheInvestor(1).into()), - POOL_A, - INVALID_TRANCHE_ID, - destination, - AMOUNT - ), - pallet_liquidity_pools::Error::::TrancheNotFound - ); - }); -} diff --git a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs index 3d7725c20a..30f3e2d6e7 100644 --- a/runtime/integration-tests/src/generic/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/generic/cases/restricted_transfers.rs @@ -15,7 +15,8 @@ use cfg_types::{ domain_address::DomainAddress, locations::RestrictedTransferLocation, tokens::{ - AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata, FilterCurrency, + default_metadata, AssetMetadata, CrossChainTransferability, CurrencyId, CustomMetadata, + FilterCurrency, }, }; use cumulus_primitives_core::WeightLimit; @@ -33,7 +34,7 @@ use crate::{ env::Env, envs::runtime_env::RuntimeEnv, utils::{ - currency::{cfg, default_metadata, CurrencyInfo, CustomCurrency}, + currency::{cfg, CurrencyInfo, CustomCurrency}, genesis, genesis::Genesis, xcm::{account_location, transferable_metadata}, diff --git a/runtime/integration-tests/src/generic/utils/currency.rs b/runtime/integration-tests/src/generic/utils/currency.rs index bec217c89e..40e0a3d2da 100644 --- a/runtime/integration-tests/src/generic/utils/currency.rs +++ b/runtime/integration-tests/src/generic/utils/currency.rs @@ -9,17 +9,6 @@ use staging_xcm::VersionedLocation; use crate::generic::config::Runtime; -pub fn default_metadata() -> AssetMetadata { - AssetMetadata { - decimals: 0, - name: Default::default(), - symbol: Default::default(), - existential_deposit: 0, - location: None, - additional: Default::default(), - } -} - const fn amount_pow(amount: Balance, exp: u32) -> Balance { amount * 10u128.pow(exp) } diff --git a/runtime/integration-tests/src/generic/utils/democracy.rs b/runtime/integration-tests/src/generic/utils/democracy.rs deleted file mode 100644 index 0edc63b782..0000000000 --- a/runtime/integration-tests/src/generic/utils/democracy.rs +++ /dev/null @@ -1,276 +0,0 @@ -use std::ops::Add; - -use cfg_primitives::{Balance, BlockNumber, CouncilCollective}; -use frame_support::{dispatch::GetDispatchInfo, traits::Bounded, weights::Weight}; -use pallet_collective::{Call as CouncilCall, MemberCount, ProposalIndex}; -use pallet_democracy::{ - AccountVote, Call as DemocracyCall, Conviction, PropIndex, ReferendumIndex, ReferendumInfo, - Vote, -}; -use pallet_preimage::Call as PreimageCall; -use parity_scale_codec::Encode; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, Hash}; - -use crate::{ - generic::{ - config::Runtime, - env::{Blocks, Env}, - envs::fudge_env::FudgeSupport, - }, - utils::accounts::Keyring, -}; - -pub fn note_preimage(call: T::RuntimeCallExt) -> T::RuntimeCallExt { - let encoded_call = call.encode(); - - PreimageCall::note_preimage { - bytes: encoded_call, - } - .into() -} - -pub fn external_propose_majority(call: T::RuntimeCallExt) -> T::RuntimeCallExt { - let hash = BlakeTwo256::hash_of(&call); - - DemocracyCall::external_propose_majority { - proposal: Bounded::Legacy { - hash, - dummy: Default::default(), - }, - } - .into() -} - -pub fn fast_track( - proposal_hash: H256, - voting_period: BlockNumber, - delay: BlockNumber, -) -> T::RuntimeCallExt { - DemocracyCall::fast_track { - proposal_hash, - voting_period, - delay, - } - .into() -} - -pub fn execute_via_democracy( - env: &mut impl Env, - council_members: Vec, - original_call: T::RuntimeCallExt, - council_threshold: MemberCount, - voting_period: BlockNumber, - starting_prop_index: PropIndex, - starting_ref_index: ReferendumIndex, -) -> (PropIndex, ReferendumIndex) { - let original_call_hash = BlakeTwo256::hash_of(&original_call); - - env.submit_later( - council_members[0].into(), - note_preimage::(original_call.clone()), - ) - .expect("Preimage noting is successful"); - - env.pass(Blocks::UntilEvent { - event: pallet_preimage::Event::::Noted { - hash: original_call_hash, - } - .into(), - limit: 3, - }); - - let external_propose_majority_call = external_propose_majority::(original_call); - - execute_collective_proposal::( - env, - &council_members, - external_propose_majority_call, - council_threshold, - starting_prop_index, - ); - - let fast_track_call = fast_track::(original_call_hash, voting_period, 0); - - execute_collective_proposal::( - env, - &council_members, - fast_track_call, - council_threshold, - starting_prop_index + 1, - ); - - let vote = AccountVote::::Standard { - vote: Vote { - aye: true, - conviction: Conviction::Locked2x, - }, - balance: 1_000_000u128, - }; - - execute_democracy_vote(env, &council_members, starting_ref_index, vote); - - (starting_prop_index + 2, starting_ref_index + 1) -} - -pub fn democracy_vote( - ref_index: ReferendumIndex, - vote: AccountVote, -) -> T::RuntimeCallExt { - DemocracyCall::vote { ref_index, vote }.into() -} - -fn execute_democracy_vote( - env: &mut impl Env, - voters: &Vec, - referendum_index: ReferendumIndex, - acc_vote: AccountVote, -) { - for acc in voters { - let ref_info = env.parachain_state(|| { - pallet_democracy::ReferendumInfoOf::::get(referendum_index).unwrap() - }); - - if let ReferendumInfo::Finished { .. } = ref_info { - // Referendum might be finished by the time all voters get to vote. - break; - } - - env.submit_later(*acc, democracy_vote::(referendum_index, acc_vote)) - .expect("Voting is successful"); - - env.pass(Blocks::UntilEvent { - event: pallet_democracy::Event::::Voted { - voter: acc.id(), - ref_index: referendum_index, - vote: acc_vote, - } - .into(), - limit: 3, - }); - } -} - -pub fn collective_propose( - proposal: T::RuntimeCallExt, - threshold: MemberCount, -) -> T::RuntimeCallExt { - let proposal_len = proposal.encode().len(); - - CouncilCall::propose { - threshold, - proposal: Box::new(proposal), - length_bound: proposal_len as u32, - } - .into() -} - -pub fn collective_vote( - proposal: H256, - index: ProposalIndex, - approve: bool, -) -> T::RuntimeCallExt { - CouncilCall::vote { - proposal, - index, - approve, - } - .into() -} - -pub fn collective_close( - proposal_hash: H256, - index: ProposalIndex, - proposal_weight_bound: Weight, - length_bound: u32, -) -> T::RuntimeCallExt { - CouncilCall::close { - proposal_hash, - index, - proposal_weight_bound, - length_bound, - } - .into() -} - -fn execute_collective_proposal( - env: &mut impl Env, - council_members: &Vec, - proposal: T::RuntimeCallExt, - council_threshold: MemberCount, - prop_index: PropIndex, -) { - let prop_hash = BlakeTwo256::hash_of(&proposal); - - env.submit_later( - council_members[0].into(), - collective_propose::(proposal.clone(), council_threshold), - ) - .expect("Collective proposal is successful"); - - env.pass(Blocks::UntilEvent { - event: pallet_collective::Event::::Proposed { - account: council_members[0].into(), - proposal_index: prop_index, - proposal_hash: prop_hash, - threshold: council_threshold, - } - .into(), - limit: 3, - }); - - for (index, acc) in council_members.iter().enumerate() { - env.submit_later(*acc, collective_vote::(prop_hash, prop_index, true)) - .expect("Collective voting is successful"); - - env.pass(Blocks::UntilEvent { - event: pallet_collective::Event::::Voted { - account: council_members[0].into(), - proposal_hash: prop_hash, - voted: true, - yes: (index + 1) as u32, - no: 0, - } - .into(), - limit: 3, - }); - } - - let proposal_weight = env.parachain_state(|| { - let external_proposal = - pallet_collective::ProposalOf::::get(prop_hash).unwrap(); - - external_proposal.get_dispatch_info().weight - }); - - env.submit_later( - council_members[0].into(), - collective_close::( - prop_hash, - prop_index, - proposal_weight.add(1.into()), - (proposal.encoded_size() + 1) as u32, - ), - ) - .expect("Collective close is successful"); - - env.pass(Blocks::UntilEvent { - event: pallet_collective::Event::::Closed { - proposal_hash: prop_hash, - yes: council_members.len() as u32, - no: 0, - } - .into(), - limit: 3, - }); - - env.check_event(pallet_collective::Event::::Approved { - proposal_hash: prop_hash, - }) - .expect("Approved event is present."); - env.check_event(pallet_collective::Event::::Executed { - proposal_hash: prop_hash, - result: Ok(()), - }) - .expect("Executed event is present."); -} diff --git a/runtime/integration-tests/src/generic/utils/mod.rs b/runtime/integration-tests/src/generic/utils/mod.rs index 992b4916ec..ddc868451d 100644 --- a/runtime/integration-tests/src/generic/utils/mod.rs +++ b/runtime/integration-tests/src/generic/utils/mod.rs @@ -9,7 +9,6 @@ //! Divide this utilities into files when it grows pub mod currency; -pub mod democracy; pub mod evm; pub mod genesis; pub mod pool; diff --git a/runtime/integration-tests/src/generic/utils/xcm.rs b/runtime/integration-tests/src/generic/utils/xcm.rs index 9f6b4d7f07..0380bf0ddf 100644 --- a/runtime/integration-tests/src/generic/utils/xcm.rs +++ b/runtime/integration-tests/src/generic/utils/xcm.rs @@ -1,5 +1,7 @@ use cfg_primitives::AccountId; -use cfg_types::tokens::{AssetMetadata, CrossChainTransferability, CustomMetadata}; +use cfg_types::tokens::{ + default_metadata, AssetMetadata, CrossChainTransferability, CustomMetadata, +}; use frame_support::{assert_ok, dispatch::RawOrigin}; use polkadot_parachain_primitives::primitives::Id; use staging_xcm::{ @@ -15,7 +17,6 @@ use crate::generic::{ handle::{PARA_ID, SIBLING_ID}, FudgeEnv, FudgeSupport, RelayRuntime, }, - utils::currency::default_metadata, }; pub fn enable_relay_to_para_communication(env: &mut FudgeEnv) { diff --git a/runtime/integration-tests/src/utils/accounts.rs b/runtime/integration-tests/src/utils/accounts.rs index 46f28d84b8..4a111daa34 100644 --- a/runtime/integration-tests/src/utils/accounts.rs +++ b/runtime/integration-tests/src/utils/accounts.rs @@ -14,6 +14,7 @@ use ethabi::ethereum_types::{H160, H256}; use frame_support::traits::OriginTrait; +use runtime_common::account_conversion::AccountConverter; use sp_core::{ecdsa, ed25519, sr25519, Hasher, Pair as PairT}; use sp_runtime::AccountId32; @@ -44,7 +45,7 @@ impl Keyring { /// NOTE: Needs to be executed in an externalities environment pub fn id_ecdsa(self) -> AccountId32 { - runtime_common::account_conversion::AccountConverter::into_account_id::(self.into()) + AccountConverter::evm_address_to_account::(self.into()) } pub fn as_multi(self) -> sp_runtime::MultiSigner {