From 083d77f46c0827af95d6d9b83e065ff9a03f2d3f Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 12 Dec 2023 11:37:24 +0100 Subject: [PATCH 1/9] Replace mock-accountant macro with mock builder pallet and Rate by Quantity --- Cargo.lock | 1 + libs/mocks/src/pools.rs | 74 ++++++++++++++++- pallets/investments/Cargo.toml | 3 + pallets/investments/src/mock.rs | 132 +++++++++++++++++++++++-------- pallets/investments/src/tests.rs | 14 ++-- 5 files changed, 185 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cec6f8cba7..f895ac38f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7877,6 +7877,7 @@ dependencies = [ name = "pallet-investments" version = "1.0.0" dependencies = [ + "cfg-mocks", "cfg-primitives", "cfg-test-utils", "cfg-traits", diff --git a/libs/mocks/src/pools.rs b/libs/mocks/src/pools.rs index fcaa809501..ba4ce059e6 100644 --- a/libs/mocks/src/pools.rs +++ b/libs/mocks/src/pools.rs @@ -1,6 +1,10 @@ #[frame_support::pallet] pub mod pallet { - use cfg_traits::{PoolInspect, PoolReserve, PriceValue, Seconds, TrancheTokenPrice}; + use cfg_traits::{ + investments::InvestmentAccountant, PoolInspect, PoolReserve, PriceValue, Seconds, + TrancheTokenPrice, + }; + use cfg_types::investments::InvestmentInfo; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::pallet_prelude::*; use mock_builder::{execute_call, register_call}; @@ -64,6 +68,42 @@ pub mod pallet { ) { register_call!(move |(a, b, c)| f(a, b, c)); } + + pub fn mock_info( + f: impl Fn( + T::TrancheCurrency, + ) -> Result< + InvestmentInfo, + DispatchError, + > + 'static, + ) { + register_call!(f); + } + + pub fn mock_balance(f: impl Fn(T::TrancheCurrency, &T::AccountId) -> T::Balance + 'static) { + register_call!(move |(a, b)| f(a, b)); + } + + pub fn mock_transfer( + f: impl Fn(T::TrancheCurrency, &T::AccountId, &T::AccountId, T::Balance) -> DispatchResult + + 'static, + ) { + register_call!(move |(a, b, c, d)| f(a, b, c, d)); + } + + #[allow(non_snake_case)] + pub fn mock_InvestmentAccountant_deposit( + f: impl Fn(&T::AccountId, T::TrancheCurrency, T::Balance) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } + + #[allow(non_snake_case)] + pub fn mock_InvestmentAccountant_withdraw( + f: impl Fn(&T::AccountId, T::TrancheCurrency, T::Balance) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } } impl PoolInspect for Pallet { @@ -88,6 +128,38 @@ pub mod pallet { } } + impl InvestmentAccountant for Pallet { + type Amount = T::Balance; + type Error = DispatchError; + type InvestmentId = T::TrancheCurrency; + type InvestmentInfo = InvestmentInfo; + + fn info(a: Self::InvestmentId) -> Result { + execute_call!(a) + } + + fn balance(a: Self::InvestmentId, b: &T::AccountId) -> Self::Amount { + execute_call!((a, b)) + } + + fn transfer( + a: Self::InvestmentId, + b: &T::AccountId, + c: &T::AccountId, + d: Self::Amount, + ) -> DispatchResult { + execute_call!((a, b, c, d)) + } + + fn deposit(a: &T::AccountId, b: Self::InvestmentId, c: Self::Amount) -> DispatchResult { + execute_call!((a, b, c)) + } + + fn withdraw(a: &T::AccountId, b: Self::InvestmentId, c: Self::Amount) -> DispatchResult { + execute_call!((a, b, c)) + } + } + impl TrancheTokenPrice for Pallet { type BalanceRatio = T::BalanceRatio; type Moment = Seconds; diff --git a/pallets/investments/Cargo.toml b/pallets/investments/Cargo.toml index 5295763165..ded078003d 100644 --- a/pallets/investments/Cargo.toml +++ b/pallets/investments/Cargo.toml @@ -29,6 +29,7 @@ frame-benchmarking = { git = "https://github.com/paritytech/substrate", default- [dev-dependencies] cfg-test-utils = { path = "../../libs/test-utils" } cfg-types = { path = "../../libs/types" } +cfg-mocks = { workspace = true, default-features = true } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } @@ -44,6 +45,7 @@ runtime-benchmarks = [ "cfg-test-utils/runtime-benchmarks", "cfg-traits/runtime-benchmarks", "cfg-types/runtime-benchmarks", + "cfg-mocks/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -67,6 +69,7 @@ try-runtime = [ "cfg-primitives/try-runtime", "cfg-test-utils/try-runtime", "cfg-traits/try-runtime", + "cfg-mocks/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", "sp-runtime/try-runtime", diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index e316376f21..b6b034b6bc 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -17,7 +17,7 @@ pub use cfg_primitives::CFG as CURRENCY; use cfg_primitives::*; use cfg_traits::{investments::OrderManager, PreConditions}; use cfg_types::{ - fixed_point::Rate, + fixed_point::Quantity, investments::{InvestmentAccount, InvestmentInfo}, orders::{FulfillmentWithPrice, TotalOrder}, tokens::CurrencyId, @@ -26,7 +26,13 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::DispatchResultWithPostInfo, parameter_types, - traits::{GenesisBuild, Nothing}, + traits::{ + tokens::{ + fungibles::{Inspect, Mutate}, + Fortitude, Precision, Preservation, + }, + GenesisBuild, Nothing, + }, RuntimeDebug, }; use orml_traits::GetByKey; @@ -38,7 +44,12 @@ use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, DispatchResult, }; -use sp_std::convert::{TryFrom, TryInto}; +use sp_std::{ + cell::RefCell, + collections::btree_map::BTreeMap, + convert::{TryFrom, TryInto}, + rc::Rc, +}; pub use crate as pallet_investments; @@ -55,7 +66,8 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Investments: pallet_investments::{Pallet, Call, Storage, Event}, OrmlTokens: orml_tokens::{Pallet, Storage, Event, Config}, - Balances: pallet_balances::{Pallet, Storage, Event} + Balances: pallet_balances::{Pallet, Storage, Event}, + MockAccountant: cfg_mocks::pallet_mock_pools, } ); @@ -136,6 +148,7 @@ impl pallet_balances::Config for MockRuntime { type WeightInfo = (); } +/* cfg_test_utils::mocks::accountant::impl_mock_accountant!( MockAccountant, MockAccountId, @@ -143,6 +156,16 @@ cfg_test_utils::mocks::accountant::impl_mock_accountant!( CurrencyId, Balance ); +*/ + +impl cfg_mocks::pallet_mock_pools::Config for MockRuntime { + type Balance = Balance; + type BalanceRatio = Quantity; + type CurrencyId = CurrencyId; + type PoolId = PoolId; + type TrancheCurrency = InvestmentId; + type TrancheId = TrancheId; +} pub struct NoopCollectHook; impl cfg_traits::StatusNotificationHook for NoopCollectHook { @@ -160,9 +183,10 @@ parameter_types! { } impl pallet_investments::Config for MockRuntime { - type Accountant = MockAccountant; + //type Accountant = MockAccountant; + type Accountant = MockAccountant; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = NoopCollectHook; type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = InvestmentId; @@ -334,8 +358,14 @@ impl TestExternalitiesBuilder { .assimilate_storage(&mut storage) .unwrap(); - MockAccountant::::init(accountant_mock::Genesis { - infos: vec![ + let mut externalities = TestExternalities::new(storage); + externalities.execute_with(|| { + // We need to set this, otherwise on genesis (i.e. 0) + // no events are stored + System::set_block_number(1); + + // Mocked behaviour for the accountant + let state = Rc::new(RefCell::new(BTreeMap::from([ ( INVESTMENT_0_0, InvestmentInfo { @@ -352,15 +382,55 @@ impl TestExternalitiesBuilder { payment_currency: AUSD_CURRENCY_ID, }, ), - ], + ]))); + + MockAccountant::mock_info({ + let state = state.clone(); + move |id| Ok(state.borrow().get(&id).unwrap().clone()) + }); + + MockAccountant::mock_balance(|id, who| OrmlTokens::balance(id.into(), who)); + + MockAccountant::mock_transfer({ + let state = state.clone(); + move |id, source, dest, amount| { + let _ = state.borrow().get(&id).unwrap(); + >::transfer( + id.into(), + source, + dest, + amount, + Preservation::Expendable, + ) + .map(|_| ()) + } + }); + + MockAccountant::mock_InvestmentAccountant_deposit({ + let state = state.clone(); + move |buyer, id, amount| { + let _ = state.borrow().get(&id).unwrap(); + >::mint_into(id.into(), buyer, amount) + .map(|_| ()) + } + }); + + MockAccountant::mock_InvestmentAccountant_withdraw({ + let state = state.clone(); + move |seller, id, amount| { + let _ = state.borrow().get(&id).unwrap(); + >::burn_from( + id.into(), + seller, + amount, + Precision::Exact, + Fortitude::Polite, + ) + .map(|_| ()) + } + }); }); - let mut externalities = TestExternalities::new(storage); - externalities.execute_with(|| { - // We need to set this, otherwise on genesis (i.e. 0) - // no events are stored - System::set_block_number(1); - }); externalities } } @@ -438,20 +508,20 @@ pub(crate) fn redeem_x_per_investor(amount: Balance) -> DispatchResult { /// # E.g. /// ```rust /// use cfg_primitives::Balance; -/// use cfg_types::Rate; +/// use cfg_types::fixed_point::Quantity; /// /// let rate = crate::mock::price_of(3, 5, 100); /// assert_eq!(rate.into_inner(), 3050000000000000000000000000) // I.e. price is 3,05 /// ``` -pub(crate) fn price_of(full: Balance, dec_n: Balance, dec_d: Balance) -> Rate { - let full = Rate::from_inner(Rate::DIV.saturating_mul(full)); - let decimals = Rate::saturating_from_rational(dec_n, dec_d); +pub(crate) fn price_of(full: Balance, dec_n: Balance, dec_d: Balance) -> Quantity { + let full = Quantity::from_inner(Quantity::DIV.saturating_mul(full)); + let decimals = Quantity::saturating_from_rational(dec_n, dec_d); full.add(decimals) } /// Creates a fulfillment of given perc and price -pub(crate) fn fulfillment_of(perc: Perquintill, price: Rate) -> FulfillmentWithPrice { +pub(crate) fn fulfillment_of(perc: Perquintill, price: Quantity) -> FulfillmentWithPrice { FulfillmentWithPrice { of_amount: perc, price, @@ -460,26 +530,26 @@ pub(crate) fn fulfillment_of(perc: Perquintill, price: Rate) -> FulfillmentWithP /// Fulfills the given fulfillment for INVESTMENT_0_0 on both invest and redeem /// side -pub(crate) fn fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { +pub(crate) fn fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { fulfill_invest_x(fulfillment)?; fulfill_redeem_x(fulfillment) } /// Fulfills the given fulfillment for INVESTMENT_0_0 on the investment side -pub(crate) fn fulfill_invest_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { +pub(crate) fn fulfill_invest_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { let _invest_orders = Investments::process_invest_orders(INVESTMENT_0_0)?; Investments::invest_fulfillment(INVESTMENT_0_0, fulfillment) } /// Fulfills the given fulfillment for INVESTMENT_0_0 on the investment side -pub(crate) fn fulfill_redeem_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { +pub(crate) fn fulfill_redeem_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { let _redeem_orders = Investments::process_redeem_orders(INVESTMENT_0_0)?; Investments::redeem_fulfillment(INVESTMENT_0_0, fulfillment) } /// Invest 50 * CURRENCY per Investor into INVESTMENT_0_0 and fulfills /// the given fulfillment. -pub(crate) fn invest_fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { +pub(crate) fn invest_fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { invest_x_per_investor(50 * CURRENCY)?; let _invest_orders = Investments::process_invest_orders(INVESTMENT_0_0)?; @@ -490,7 +560,7 @@ pub(crate) fn invest_fulfill_x(fulfillment: FulfillmentWithPrice) -> Dispa /// the given fulfillment. pub(crate) fn invest_x_fulfill_x( invest_per_investor: Balance, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, ) -> DispatchResult { invest_x_per_investor(invest_per_investor)?; @@ -502,7 +572,7 @@ pub(crate) fn invest_x_fulfill_x( /// the given fulfillment. pub(crate) fn invest_x_per_fulfill_x( invest_per_investor: Vec<(MockAccountId, Balance)>, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, ) -> DispatchResult { for (who, amount) in invest_per_investor { Investments::update_invest_order(RuntimeOrigin::signed(who), INVESTMENT_0_0, amount)?; @@ -515,7 +585,7 @@ pub(crate) fn invest_x_per_fulfill_x( /// and fulfills the given fulfillment. pub(crate) fn invest_x_runner_fulfill_x( invest_per_investor: Balance, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, runner: F, ) -> DispatchResult where @@ -529,7 +599,7 @@ where /// Redeem 50 * CURRENCY per TrancheHolder into INVESTMENT_0_0 and fulfills /// the given fulfillment. -pub(crate) fn redeem_fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { +pub(crate) fn redeem_fulfill_x(fulfillment: FulfillmentWithPrice) -> DispatchResult { redeem_x_per_investor(50 * CURRENCY)?; let _redeem_orders = Investments::process_redeem_orders(INVESTMENT_0_0); @@ -540,7 +610,7 @@ pub(crate) fn redeem_fulfill_x(fulfillment: FulfillmentWithPrice) -> Dispa /// the given fulfillment. pub(crate) fn redeem_x_fulfill_x( redeem_per_investor: Balance, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, ) -> DispatchResult { redeem_x_per_investor(redeem_per_investor)?; @@ -552,7 +622,7 @@ pub(crate) fn redeem_x_fulfill_x( /// the given fulfillment. pub(crate) fn redeem_x_per_fulfill_x( redeem_per_investor: Vec<(MockAccountId, Balance)>, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, ) -> DispatchResult { for (who, amount) in redeem_per_investor { Investments::update_redeem_order(RuntimeOrigin::signed(who), INVESTMENT_0_0, amount)?; @@ -565,7 +635,7 @@ pub(crate) fn redeem_x_per_fulfill_x( /// closure and fulfills the given fulfillment. pub(crate) fn redeem_x_runner_fulfill_x( redeem_per_investor: Balance, - fulfillment: FulfillmentWithPrice, + fulfillment: FulfillmentWithPrice, runner: F, ) -> DispatchResult where diff --git a/pallets/investments/src/tests.rs b/pallets/investments/src/tests.rs index c9d7d74708..87be5305dc 100644 --- a/pallets/investments/src/tests.rs +++ b/pallets/investments/src/tests.rs @@ -11,7 +11,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_types::fixed_point::Rate; +use cfg_types::fixed_point::Quantity; use frame_support::{assert_noop, assert_ok}; use pallet_investments::Event; use sp_arithmetic::{traits::Saturating, Perquintill}; @@ -622,7 +622,7 @@ fn update_redeem_fails_when_collect_needed() { fn fulfillment_flow_for_everything_works() { TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 2, 10); + let PRICE: Quantity = price_of(1, 2, 10); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT = 50 * CURRENCY; #[allow(non_snake_case)] @@ -821,7 +821,7 @@ fn fulfillment_partially_works_low_price() { // * Collects and orders from users must overflow correctly too TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 288, 334); + let PRICE: Quantity = price_of(1, 288, 334); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT = 50 * CURRENCY; #[allow(non_snake_case)] @@ -1507,7 +1507,7 @@ fn fulfillment_partially_works_high_price() { // * Collects and orders from users must overflow correctly too TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 288, 335); + let PRICE: Quantity = price_of(1, 288, 335); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT = 50 * CURRENCY; #[allow(non_snake_case)] @@ -2183,7 +2183,7 @@ fn fulfillment_partially_works_high_price() { fn fulfillment_of_zero_works() { TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 20, 10); + let PRICE: Quantity = price_of(1, 20, 10); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT = 50 * CURRENCY; #[allow(non_snake_case)] @@ -2506,7 +2506,7 @@ fn fulfillment_of_zero_works() { fn collecting_fully_works() { TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 288, 334); + let PRICE: Quantity = price_of(1, 288, 334); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT_A = 50 * CURRENCY; #[allow(non_snake_case)] @@ -2818,7 +2818,7 @@ fn collecting_fully_works() { fn collecting_over_max_works() { TestExternalitiesBuilder::build().execute_with(|| { #[allow(non_snake_case)] - let PRICE: Rate = price_of(1, 288, 335); + let PRICE: Quantity = price_of(1, 288, 335); #[allow(non_snake_case)] let SINGLE_REDEEM_AMOUNT = 50 * CURRENCY; #[allow(non_snake_case)] From 3f6ef816a20fb1cdb5a88dffafc8040ef9d0700c Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 12 Dec 2023 11:50:04 +0100 Subject: [PATCH 2/9] remove unused test-utils mocks --- Cargo.lock | 1 - libs/test-utils/src/mocks/accountant.rs | 244 ----------- libs/test-utils/src/mocks/authority_origin.rs | 55 --- libs/test-utils/src/mocks/mod.rs | 3 - libs/test-utils/src/mocks/order_manager.rs | 412 ------------------ pallets/investments/Cargo.toml | 3 - pallets/investments/src/mock.rs | 10 - 7 files changed, 728 deletions(-) delete mode 100644 libs/test-utils/src/mocks/accountant.rs delete mode 100644 libs/test-utils/src/mocks/authority_origin.rs delete mode 100644 libs/test-utils/src/mocks/order_manager.rs diff --git a/Cargo.lock b/Cargo.lock index f895ac38f8..c51edff90b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7879,7 +7879,6 @@ version = "1.0.0" dependencies = [ "cfg-mocks", "cfg-primitives", - "cfg-test-utils", "cfg-traits", "cfg-types", "frame-benchmarking", diff --git a/libs/test-utils/src/mocks/accountant.rs b/libs/test-utils/src/mocks/accountant.rs deleted file mode 100644 index 7b27882cf5..0000000000 --- a/libs/test-utils/src/mocks/accountant.rs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2021 Centrifuge Foundation (centrifuge.io). -// -// This file is part of the Centrifuge chain project. -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -/// Exposes a struct $name that implements the `trait Accountant`. The struct -/// expects one generic parameter that implements the fungibles traits -/// `Inspect`, `Mutate` and `Transfer`. -/// -/// * E.g.: `MockAccountant` -/// -/// # Example macro usage: -/// ```ignore -/// use cfg_traits::impl_mock_accountant; -/// use cfg_primitives::{PoolId, TrancheId, Balance}; -/// use cfg_types::tokens::CurrencyId; -/// use frame_support::traits::fungibles::{Inspect, Mutate, Transfer}; -/// use frame_support::traits::GenesisBuild; -/// -/// /// The used account id for this mock -/// type AccountId = u64; -/// -/// enum InvestmentId { -/// Tranches(PoolId, TrancheId), -/// } -/// -/// impl Into for InvestmentId { -/// fn into(self) -> CurrencyId { -/// CurrencyId::Tranche(self.0, self.1) -/// } -/// } -/// -/// -/// impl_mock_accountant!( -/// MockAccountant, -/// AccountId, -/// InvestmentId, -/// CurrencyId, -/// Balance -/// ); -/// -/// // Using the `GenesisConfig` -/// use accountant_mock::InvestmentInfo; -/// let storage = GenesisBuild::init(&accountant_mock::Genesis { -/// infos: vec![ -/// ( -/// InvestmentId::Tranche(0, [0;16]), -/// accountant_mock::InvestmentInfo { -/// owner: 1, -/// id: InvestmentId::Tranches(0, [0;16]), -/// payment_currency: AUSD_CURRENCY_ID -/// } -/// ) -/// ] -/// }).expect("Must not fail"); -/// ``` -#[macro_export] -macro_rules! impl_mock_accountant { - ($name:ident, $account_id:ty, $investment_id:ty, $currency_id:ty, $balance:ty) => { - pub use accountant_mock::$name; - - mod accountant_mock { - use std::borrow::{Borrow as _, BorrowMut as _}; - - use __private::STATE as __private_STATE; - use frame_support::traits::tokens::{Fortitude, Precision, Preservation}; - - use super::*; - - pub type InvestmentInfo = - cfg_types::investments::InvestmentInfo<$account_id, $currency_id, $investment_id>; - - #[derive(Default)] - pub struct Genesis { - pub infos: Vec<($investment_id, InvestmentInfo)>, - } - - pub struct $name(sp_std::marker::PhantomData); - - impl $name { - pub fn init(genesis: Genesis) { - __private_STATE.with(|s| { - let mut state = s.borrow_mut(); - - for (id, info) in &genesis.infos { - state.add(id.clone(), info.clone()) - } - }) - } - } - - impl cfg_traits::investments::InvestmentAccountant<$account_id> for $name - where - Tokens: frame_support::traits::tokens::fungibles::Mutate<$account_id> - // + frame_support::traits::tokens::fungibles::Transfer<$account_id> - + frame_support::traits::tokens::fungibles::Inspect< - $account_id, - Balance = $balance, - AssetId = $currency_id, - >, - $investment_id: - Into< - >::AssetId, - >, - { - type Amount = $balance; - type Error = frame_support::dispatch::DispatchError; - type InvestmentId = $investment_id; - type InvestmentInfo = InvestmentInfo; - - fn info(id: Self::InvestmentId) -> Result { - __private_STATE.with(|s| s.borrow().info(&id)) - } - - fn balance(id: Self::InvestmentId, who: &$account_id) -> Self::Amount { - Tokens::balance(id.into(), who) - } - - fn transfer( - id: Self::InvestmentId, - source: &$account_id, - dest: &$account_id, - amount: Self::Amount, - ) -> Result<(), Self::Error> { - let _ = __private_STATE.with(|s| s.borrow().info(&id))?; - - Tokens::transfer(id.into(), source, dest, amount, Preservation::Expendable) - .map(|_| ()) - } - - fn deposit( - buyer: &$account_id, - id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error> { - let _ = __private_STATE.with(|s| s.borrow().info(&id))?; - - Tokens::mint_into(id.into(), buyer, amount).map(|_| ()) - } - - fn withdraw( - seller: &$account_id, - id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error> { - let _ = __private_STATE.with(|s| s.borrow().info(&id))?; - - Tokens::burn_from( - id.into(), - seller, - amount, - Precision::Exact, - Fortitude::Polite, - ) - .map(|_| ()) - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl cfg_traits::benchmarking::FundedPoolBenchmarkHelper for $name { - type AccountId = $account_id; - type Balance = $balance; - type PoolId = (); - - fn bench_create_funded_pool(_: Self::PoolId, _: &Self::AccountId) {} - - fn bench_investor_setup(_: Self::PoolId, _: Self::AccountId, _: Self::Balance) {} - } - - #[cfg(feature = "runtime-benchmarks")] - impl cfg_traits::benchmarking::InvestmentIdBenchmarkHelper for $name { - type InvestmentId = $investment_id; - type PoolId = (); - - fn bench_default_investment_id(_: Self::PoolId) -> Self::InvestmentId { - Self::InvestmentId::default() - } - } - - mod __private { - use super::*; - - pub struct AccountantState { - infos: Vec<($investment_id, InvestmentInfo)>, - } - - impl AccountantState { - pub fn new() -> Self { - Self { - infos: Vec::default(), - } - } - - pub fn info( - &self, - investment_id: &$investment_id, - ) -> Result { - for (curr_id, info) in &self.infos { - if curr_id == investment_id { - return Ok(info.clone()); - } - } - - Err(frame_support::dispatch::DispatchError::Other( - "No info for investment_id available", - )) - } - - pub fn add(&mut self, investment_id: $investment_id, info: InvestmentInfo) { - // NOTE: We deliberately update the info here as add() is only called - // upon init(). We assume, if we are running in the - // same thread this means a new initialization is wanted. - for (curr_id, curr_info) in &mut self.infos { - if *curr_id == investment_id { - *curr_info = info; - return; - } - } - - self.infos.push((investment_id, info)) - } - } - - thread_local! { - pub static STATE: sp_std::cell::RefCell< - AccountantState, - > = sp_std::cell::RefCell::new(AccountantState::new()); - } - } - } - }; -} - -pub use impl_mock_accountant; diff --git a/libs/test-utils/src/mocks/authority_origin.rs b/libs/test-utils/src/mocks/authority_origin.rs deleted file mode 100644 index d7fc4bdeb0..0000000000 --- a/libs/test-utils/src/mocks/authority_origin.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2021 Centrifuge Foundation (centrifuge.io). -// -// This file is part of the Centrifuge chain project. -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -use cfg_types::tokens::CurrencyId; -use frame_support::traits::{EnsureOrigin, EnsureOriginWithArg}; -use frame_system::RawOrigin; -use sp_std::marker::PhantomData; - -type AccountId = u64; - -/// This OrmlAssetRegistry::AuthorityOrigin implementation is used for our -/// pallet-loans and pallet-pool-system Mocks. We overwrite this because of the -/// `type AccountId = u64`. In the runtime tests, we use proper AccountIds, in -/// the Mocks, we use 1,2,3,... . Therefore, we implement `AuthorityOrigin` and -/// use the `u64` type for the AccountId. -/// -/// Use this implementation only when setting up Mocks with simple AccountIds. -pub struct AuthorityOrigin< - // The origin type - Origin, - // The default EnsureOrigin impl used to authorize all - // assets besides tranche tokens. - DefaultEnsureOrigin, ->(PhantomData<(Origin, DefaultEnsureOrigin)>); - -impl< - Origin: Into, Origin>> + From>, - EnsureRoot: EnsureOrigin, - > EnsureOriginWithArg> for AuthorityOrigin -{ - type Success = (); - - fn try_origin(origin: Origin, asset_id: &Option) -> Result { - match asset_id { - // Only the pools pallet should directly register/update tranche tokens - Some(CurrencyId::Tranche(_, _)) => Err(origin), - - // Any other `asset_id` defaults to EnsureRoot - _ => EnsureRoot::try_origin(origin).map(|_| ()), - } - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin(_: &Option) -> Result { - Err(()) - } -} diff --git a/libs/test-utils/src/mocks/mod.rs b/libs/test-utils/src/mocks/mod.rs index 9b48d90110..53cfd9558e 100644 --- a/libs/test-utils/src/mocks/mod.rs +++ b/libs/test-utils/src/mocks/mod.rs @@ -13,8 +13,5 @@ //! Mocks of traits for usage in pallet-tests. //! Also does contain implementations for Substrate based traits for testing -pub mod accountant; -pub mod authority_origin; pub mod nav; -pub mod order_manager; pub mod orml_asset_registry; diff --git a/libs/test-utils/src/mocks/order_manager.rs b/libs/test-utils/src/mocks/order_manager.rs deleted file mode 100644 index 3e318e27f4..0000000000 --- a/libs/test-utils/src/mocks/order_manager.rs +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2021 Centrifuge Foundation (centrifuge.io). -// -// This file is part of the Centrifuge chain project. -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use cfg_traits::investments::{ - Investment, InvestmentAccountant, OrderManager, TrancheCurrency, - }; - use cfg_types::{ - investments::InvestmentInfo, - orders::{FulfillmentWithPrice, TotalOrder}, - }; - use frame_support::{ - pallet_prelude::*, - traits::{ - fungibles::{Inspect, Mutate}, - tokens::Preservation, - }, - PalletId, - }; - use frame_system::pallet_prelude::BlockNumberFor; - use sp_runtime::{traits::AccountIdConversion, FixedPointNumber, FixedPointOperand}; - - pub struct OrderManagerAccount; - - impl OrderManagerAccount { - pub const LOCAL_ID: PalletId = PalletId(*b"OrdrMngr"); - - pub fn get() -> T::AccountId { - OrderManagerAccount::LOCAL_ID.into_account_truncating() - } - } - - type BalanceOf = - <::Tokens as Inspect<::AccountId>>::Balance; - type CurrencyOf = - <::Tokens as Inspect<::AccountId>>::AssetId; - - #[pallet::config] - pub trait Config: frame_system::Config - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: - MaxEncodedLen + MaybeSerializeDeserialize, - { - type FundsAccount: Get; - - type Accountant: InvestmentAccountant< - Self::AccountId, - Amount = BalanceOf, - Error = DispatchError, - InvestmentId = Self::InvestmentId, - InvestmentInfo = InvestmentInfo, Self::InvestmentId>, - >; - - type PoolId: Member + Parameter + Default + Copy + MaxEncodedLen; - - type TrancheId: Member + Parameter + Default + Copy + MaxEncodedLen; - - type InvestmentId: Member - + Parameter - + Copy - + MaxEncodedLen - + MaybeSerializeDeserialize - + Into> - + TrancheCurrency; - - type Rate: FixedPointNumber>; - - type Tokens: Inspect + Mutate; - } - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::genesis_config] - pub struct GenesisConfig - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - pub invest_orders: Vec<(T::InvestmentId, BalanceOf)>, - pub redeem_orders: Vec<(T::InvestmentId, BalanceOf)>, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - fn default() -> Self { - Self { - invest_orders: Default::default(), - redeem_orders: Default::default(), - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - fn build(&self) { - for (id, amount) in &self.invest_orders { - InvestOrders::::insert(*id, TotalOrder { amount: *amount }); - } - for (id, amount) in &self.redeem_orders { - RedeemOrders::::insert(*id, TotalOrder { amount: *amount }); - } - } - } - - #[pallet::storage] - pub type InvestOrders = - StorageMap<_, Blake2_128Concat, T::InvestmentId, TotalOrder>>; - - #[pallet::storage] - pub type RedeemOrders = - StorageMap<_, Blake2_128Concat, T::InvestmentId, TotalOrder>>; - - #[pallet::hooks] - impl Hooks> for Pallet - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - // TODO: Remove once we are on Substrate:polkadot-v0.9.29 - } - #[pallet::call] - impl Pallet - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - // TODO: Remove once we are on Substrate:polkadot-v0.9.29 - } - - impl Pallet - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - /// **Test Method** - /// - /// Moves funds from the `T::FundsAccount` to the local - /// `OrderManagerAccount` - pub fn update_invest_order( - investment_id: T::InvestmentId, - amount: BalanceOf, - ) -> DispatchResult { - let mut orders = InvestOrders::::get(investment_id).unwrap_or_default(); - orders.amount += amount; - InvestOrders::::insert(investment_id, orders); - - let details = T::Accountant::info(investment_id)?; - - T::Tokens::transfer( - details.payment_currency, - &T::FundsAccount::get().into_account_truncating(), - &OrderManagerAccount::get::(), - amount, - Preservation::Expendable, - ) - .map(|_| ()) - } - - /// **Test Method** - /// - /// DOES NOT move funds. We assume that all received `TrancheTokens` - /// stay in the given `OrderManagerAccount` while testing. Hence, if - /// redeemptions should be locked we do not need to move them. - pub fn update_redeem_order( - investment_id: T::InvestmentId, - amount: BalanceOf, - ) -> DispatchResult { - let mut orders = RedeemOrders::::get(investment_id).unwrap_or_default(); - orders.amount += amount; - RedeemOrders::::insert(investment_id, orders); - - // NOTE: TrancheTokens NEVER leave the TEST_PALLET_ID account and hence we can - // keep them here and need no transfer. - - Ok(()) - } - } - - impl Investment for Pallet - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - type Amount = BalanceOf; - type CurrencyId = CurrencyOf; - type Error = DispatchError; - type InvestmentId = T::InvestmentId; - - fn update_investment( - _: &T::AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error> { - Self::update_invest_order(investment_id, amount) - } - - fn accepted_payment_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool { - T::Accountant::info(investment_id) - .map(|info| info.payment_currency == currency) - .unwrap_or(false) - } - - fn investment( - _: &T::AccountId, - investment_id: Self::InvestmentId, - ) -> Result { - Ok(InvestOrders::::get(investment_id) - .unwrap_or_default() - .amount) - } - - fn update_redemption( - _: &T::AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error> { - Self::update_redeem_order(investment_id, amount) - } - - fn accepted_payout_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool { - T::Accountant::info(investment_id) - .map(|info| info.payment_currency == currency) - .unwrap_or(false) - } - - fn redemption( - _: &T::AccountId, - investment_id: Self::InvestmentId, - ) -> Result { - Ok(RedeemOrders::::get(investment_id) - .unwrap_or_default() - .amount) - } - - fn investment_requires_collect( - _investor: &T::AccountId, - _investment_id: Self::InvestmentId, - ) -> bool { - unimplemented!("not needed here, could also default to false") - } - - fn redemption_requires_collect( - _investor: &T::AccountId, - _investment_id: Self::InvestmentId, - ) -> bool { - unimplemented!("not needed here, could also default to false") - } - } - - impl OrderManager for Pallet - where - >::Balance: - From + FixedPointOperand + MaxEncodedLen + MaybeSerializeDeserialize, - >::AssetId: MaxEncodedLen + MaybeSerializeDeserialize, - { - type Error = DispatchError; - type Fulfillment = FulfillmentWithPrice; - type InvestmentId = T::InvestmentId; - type Orders = TotalOrder>; - - /// When called the manager return the current - /// invest orders for the given investment class. - fn process_invest_orders( - asset_id: Self::InvestmentId, - ) -> Result { - Ok(InvestOrders::::get(asset_id).unwrap_or_default()) - } - - /// When called the manager return the current - /// redeem orders for the given investment class. - fn process_redeem_orders( - asset_id: Self::InvestmentId, - ) -> Result { - Ok(RedeemOrders::::get(asset_id).unwrap_or_default()) - } - - fn invest_orders(asset_id: Self::InvestmentId) -> Self::Orders { - InvestOrders::::get(asset_id).unwrap_or_default() - } - - fn redeem_orders(asset_id: Self::InvestmentId) -> Self::Orders { - RedeemOrders::::get(asset_id).unwrap_or_default() - } - - /// Signals the manager that the previously - /// fetch invest orders for a given investment class - /// will be fulfilled by fulfillment. - fn invest_fulfillment( - asset_id: Self::InvestmentId, - fulfillment: Self::Fulfillment, - ) -> Result<(), Self::Error> { - let orders = InvestOrders::::get(asset_id).unwrap_or_default(); - InvestOrders::::insert(asset_id, TotalOrder::default()); - - // Move tokens to pools - let tokens_to_transfer_to_pool = fulfillment.of_amount.mul_floor(orders.amount); - let details = T::Accountant::info(asset_id)?; - T::Tokens::transfer( - details.payment_currency, - &OrderManagerAccount::get::(), - &details.owner, - tokens_to_transfer_to_pool, - Preservation::Preserve, - ) - .expect("Transferring must work. Qed."); - - // Update local order - InvestOrders::::insert( - asset_id, - TotalOrder { - amount: orders.amount - tokens_to_transfer_to_pool, - }, - ); - - // Mint tranche tokens into test pallet-id - let tranche_tokens_to_mint = fulfillment - .price - .reciprocal() - .unwrap() - .checked_mul_int(tokens_to_transfer_to_pool) - .unwrap(); - T::Accountant::deposit( - &OrderManagerAccount::get::(), - asset_id, - tranche_tokens_to_mint, - ) - .expect("Depositing must work. Qed."); - - Ok(()) - } - - /// Signals the manager that the previously - /// fetch redeem orders for a given investment class - /// will be fulfilled by fulfillment. - fn redeem_fulfillment( - asset_id: Self::InvestmentId, - fulfillment: Self::Fulfillment, - ) -> Result<(), Self::Error> { - let orders = RedeemOrders::::get(asset_id).unwrap_or_default(); - RedeemOrders::::insert(asset_id, TotalOrder::default()); - - let tranche_tokens_to_burn_from_test_pallet = - fulfillment.of_amount.mul_floor(orders.amount); - T::Accountant::withdraw( - &OrderManagerAccount::get::(), - asset_id, - tranche_tokens_to_burn_from_test_pallet, - ) - .expect("Withdrawing must work. Qed."); - - // Update local order - RedeemOrders::::insert( - asset_id, - TotalOrder { - amount: orders.amount - tranche_tokens_to_burn_from_test_pallet, - }, - ); - - let payment_currency_to_move_to_order_manager = fulfillment - .price - .checked_mul_int(tranche_tokens_to_burn_from_test_pallet) - .unwrap(); - let details = T::Accountant::info(asset_id)?; - T::Tokens::transfer( - details.payment_currency, - &details.owner, - &OrderManagerAccount::get::(), - payment_currency_to_move_to_order_manager, - Preservation::Expendable, - ) - .expect("Transferring must work. Qed."); - - Ok(()) - } - } -} diff --git a/pallets/investments/Cargo.toml b/pallets/investments/Cargo.toml index ded078003d..296860a2dc 100644 --- a/pallets/investments/Cargo.toml +++ b/pallets/investments/Cargo.toml @@ -27,7 +27,6 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" } [dev-dependencies] -cfg-test-utils = { path = "../../libs/test-utils" } cfg-types = { path = "../../libs/types" } cfg-mocks = { workspace = true, default-features = true } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } @@ -42,7 +41,6 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0 default = ["std"] runtime-benchmarks = [ "cfg-primitives/runtime-benchmarks", - "cfg-test-utils/runtime-benchmarks", "cfg-traits/runtime-benchmarks", "cfg-types/runtime-benchmarks", "cfg-mocks/runtime-benchmarks", @@ -67,7 +65,6 @@ std = [ ] try-runtime = [ "cfg-primitives/try-runtime", - "cfg-test-utils/try-runtime", "cfg-traits/try-runtime", "cfg-mocks/try-runtime", "frame-support/try-runtime", diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index b6b034b6bc..b9dbe8fa27 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -148,16 +148,6 @@ impl pallet_balances::Config for MockRuntime { type WeightInfo = (); } -/* -cfg_test_utils::mocks::accountant::impl_mock_accountant!( - MockAccountant, - MockAccountId, - InvestmentId, - CurrencyId, - Balance -); -*/ - impl cfg_mocks::pallet_mock_pools::Config for MockRuntime { type Balance = Balance; type BalanceRatio = Quantity; From 851d43593e8a392bfd69df3c9dd26947d05fc0f7 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Tue, 12 Dec 2023 11:57:57 +0100 Subject: [PATCH 3/9] add warn --- libs/test-utils/src/mocks/mod.rs | 4 ++++ pallets/investments/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/test-utils/src/mocks/mod.rs b/libs/test-utils/src/mocks/mod.rs index 53cfd9558e..7b65d6253f 100644 --- a/libs/test-utils/src/mocks/mod.rs +++ b/libs/test-utils/src/mocks/mod.rs @@ -15,3 +15,7 @@ pub mod nav; pub mod orml_asset_registry; + +// README! Before adding a mock here, +// evaluate first if the mock can be built using mock-builder under +// `cfg-mocks` crate. diff --git a/pallets/investments/Cargo.toml b/pallets/investments/Cargo.toml index 296860a2dc..805ffee762 100644 --- a/pallets/investments/Cargo.toml +++ b/pallets/investments/Cargo.toml @@ -27,8 +27,8 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.43" } [dev-dependencies] -cfg-types = { path = "../../libs/types" } cfg-mocks = { workspace = true, default-features = true } +cfg-types = { path = "../../libs/types" } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.43" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } From 03a053e74b9d263ed6d85825b787c14bcf23a044 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 07:54:08 +0100 Subject: [PATCH 4/9] update mock-builder dependency --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c51edff90b..38ba08430c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6358,7 +6358,7 @@ dependencies = [ [[package]] name = "mock-builder" version = "0.1.1" -source = "git+https://github.com/foss3/runtime-pallet-library?branch=polkadot-v0.9.43#8a67d0cf0e7c2544e918bb01ef9f70fc1c6108ec" +source = "git+https://github.com/foss3/runtime-pallet-library?branch=polkadot-v0.9.43#ec9159d06c01f2ce3d9733779c6cfb2be9e6cc10" dependencies = [ "frame-support", ] From 6aeed9fbba14141782a46dda37c988b65f832c8a Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 08:09:33 +0100 Subject: [PATCH 5/9] improve mock configuration --- pallets/investments/src/mock.rs | 144 ++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index b9dbe8fa27..a696725982 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -42,7 +42,7 @@ use sp_arithmetic::{FixedPointNumber, Perquintill}; use sp_io::TestExternalities; use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, - DispatchResult, + DispatchError, DispatchResult, }; use sp_std::{ cell::RefCell, @@ -355,76 +355,90 @@ impl TestExternalitiesBuilder { System::set_block_number(1); // Mocked behaviour for the accountant - let state = Rc::new(RefCell::new(BTreeMap::from([ - ( - INVESTMENT_0_0, - InvestmentInfo { - owner: Owner::get(), - id: INVESTMENT_0_0, - payment_currency: AUSD_CURRENCY_ID, - }, - ), - ( - INVESTMENT_0_1, - InvestmentInfo { - owner: Owner::get(), - id: INVESTMENT_0_1, - payment_currency: AUSD_CURRENCY_ID, - }, - ), - ]))); - - MockAccountant::mock_info({ - let state = state.clone(); - move |id| Ok(state.borrow().get(&id).unwrap().clone()) - }); - - MockAccountant::mock_balance(|id, who| OrmlTokens::balance(id.into(), who)); - - MockAccountant::mock_transfer({ - let state = state.clone(); - move |id, source, dest, amount| { - let _ = state.borrow().get(&id).unwrap(); - >::transfer( - id.into(), - source, - dest, - amount, - Preservation::Expendable, - ) - .map(|_| ()) - } - }); - - MockAccountant::mock_InvestmentAccountant_deposit({ - let state = state.clone(); - move |buyer, id, amount| { - let _ = state.borrow().get(&id).unwrap(); - >::mint_into(id.into(), buyer, amount) - .map(|_| ()) - } - }); - - MockAccountant::mock_InvestmentAccountant_withdraw({ - let state = state.clone(); - move |seller, id, amount| { - let _ = state.borrow().get(&id).unwrap(); - >::burn_from( - id.into(), - seller, - amount, - Precision::Exact, - Fortitude::Polite, - ) - .map(|_| ()) - } - }); + configure_accountant_mock(); }); externalities } } +fn configure_accountant_mock() { + let state = Rc::new(RefCell::new(BTreeMap::from([ + ( + INVESTMENT_0_0, + InvestmentInfo { + owner: Owner::get(), + id: INVESTMENT_0_0, + payment_currency: AUSD_CURRENCY_ID, + }, + ), + ( + INVESTMENT_0_1, + InvestmentInfo { + owner: Owner::get(), + id: INVESTMENT_0_1, + payment_currency: AUSD_CURRENCY_ID, + }, + ), + ]))); + + fn get( + state: &Rc>>, + id: InvestmentId, + ) -> Result { + state + .borrow() + .get(&id) + .cloned() + .ok_or(DispatchError::Other("Not found")) + } + + MockAccountant::mock_info({ + let state = state.clone(); + move |id| get(&state, id) + }); + + MockAccountant::mock_balance(|id, who| OrmlTokens::balance(id.into(), who)); + + MockAccountant::mock_transfer({ + let state = state.clone(); + move |id, source, dest, amount| { + let _ = get(&state, id)?; + >::transfer( + id.into(), + source, + dest, + amount, + Preservation::Expendable, + ) + .map(|_| ()) + } + }); + + MockAccountant::mock_InvestmentAccountant_deposit({ + let state = state.clone(); + move |buyer, id, amount| { + let _ = get(&state, id)?; + >::mint_into(id.into(), buyer, amount).map(|_| ()) + } + }); + + MockAccountant::mock_InvestmentAccountant_withdraw({ + let state = state.clone(); + move |seller, id, amount| { + let _ = get(&state, id)?; + >::burn_from( + id.into(), + seller, + amount, + Precision::Exact, + Fortitude::Polite, + ) + .map(|_| ()) + } + }); +} + pub(crate) fn last_event() -> RuntimeEvent { let events = frame_system::Pallet::::events(); // compare to the last event record From e78c0c3eaf12f0cc25ff197e7d9040eceb5c19e1 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 08:26:14 +0100 Subject: [PATCH 6/9] modify hardcoded values in tests due rounding issues --- pallets/investments/src/tests.rs | 56 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/pallets/investments/src/tests.rs b/pallets/investments/src/tests.rs index 87be5305dc..ab7f71ca6e 100644 --- a/pallets/investments/src/tests.rs +++ b/pallets/investments/src/tests.rs @@ -1289,11 +1289,11 @@ fn fulfillment_partially_works_low_price() { { assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), AUSD_CURRENCY_ID), - 207245508982035928145 + 207245508982035928140 ); assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), INVESTMENT_0_0.into()), - 175369774919614147912 + 175369774919614147910 ); } @@ -1347,6 +1347,8 @@ fn fulfillment_partially_works_low_price() { .unwrap() ) .unwrap() + // Due to rounding issues + -1 ); assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), INVESTMENT_0_0.into()), @@ -1362,7 +1364,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - 26848874598070739546 + 26848874598070739548 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorB::get()), @@ -1370,7 +1372,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - 26848874598070739546 + 26848874598070739548 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorC::get()), @@ -1378,7 +1380,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorC::get(), INVESTMENT_0_0.into()), - 26848874598070739546 + 26848874598070739548 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorD::get()), @@ -1398,7 +1400,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - 93113772455089820355 + 93113772455089820349 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderB::get()), @@ -1406,7 +1408,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(TrancheHolderB::get(), AUSD_CURRENCY_ID), - 93113772455089820355 + 93113772455089820349 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderC::get()), @@ -1414,7 +1416,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(TrancheHolderC::get(), AUSD_CURRENCY_ID), - 93113772455089820355 + 93113772455089820349 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderD::get()), @@ -1426,7 +1428,7 @@ fn fulfillment_partially_works_low_price() { // about this. assert_eq!( free_balance_of(TrancheHolderD::get(), AUSD_CURRENCY_ID), - 93113772455089820358 + 93113772455089820348 ); // UserOrders are empty @@ -1975,11 +1977,11 @@ fn fulfillment_partially_works_high_price() { { assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), AUSD_CURRENCY_ID), - 207194029850746268657 + 207194029850746268660 ); assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), INVESTMENT_0_0.into()), - 175377207062600321028 + 175377207062600321050 ); } @@ -2024,11 +2026,11 @@ fn fulfillment_partially_works_high_price() { { assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), AUSD_CURRENCY_ID), - 353343283582089552240 + 353343283582089552270 ); assert_eq!( free_balance_of(investment_account(INVESTMENT_0_0), INVESTMENT_0_0.into()), - 96789727126805778492 + 96789727126805778559 ); } @@ -2040,7 +2042,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - 26886035313001605134 + 26886035313001605098 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorB::get()), @@ -2048,7 +2050,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - 26886035313001605134 + 26886035313001605098 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorC::get()), @@ -2056,7 +2058,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorC::get(), INVESTMENT_0_0.into()), - 26886035313001605134 + 26886035313001605098 ); assert_ok!(collect_both( RuntimeOrigin::signed(InvestorD::get()), @@ -2068,7 +2070,7 @@ fn fulfillment_partially_works_high_price() { // about this. assert_eq!( free_balance_of(InvestorD::get(), INVESTMENT_0_0.into()), - 26886035313001605135 + 26886035313001605098 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderA::get()), @@ -2076,7 +2078,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - 92985074626865671639 + 92985074626865671648 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderB::get()), @@ -2084,7 +2086,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(TrancheHolderB::get(), AUSD_CURRENCY_ID), - 92985074626865671639 + 92985074626865671648 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderC::get()), @@ -2092,7 +2094,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(TrancheHolderC::get(), AUSD_CURRENCY_ID), - 92985074626865671639 + 92985074626865671648 ); assert_ok!(collect_both( RuntimeOrigin::signed(TrancheHolderD::get()), @@ -2104,7 +2106,7 @@ fn fulfillment_partially_works_high_price() { // about this. assert_eq!( free_balance_of(TrancheHolderD::get(), AUSD_CURRENCY_ID), - 92985074626865671638 + 92985074626865671647 ); // UserOrders are empty @@ -2859,7 +2861,7 @@ fn collecting_over_max_works() { who: InvestorA::get(), processed_orders: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], collection: InvestCollection { - payout_investment_invest: 23999169253290529690, + payout_investment_invest: 23999169253290529658, remaining_investment_invest: 5368709120000000000 }, outcome: CollectOutcome::PartiallyCollected, @@ -2884,7 +2886,7 @@ fn collecting_over_max_works() { who: InvestorA::get(), processed_orders: vec![10], collection: InvestCollection { - payout_investment_invest: 2886866059711075441, + payout_investment_invest: 2886866059711075437, remaining_investment_invest: 0 }, outcome: CollectOutcome::FullyCollected @@ -2897,7 +2899,7 @@ fn collecting_over_max_works() { ); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - 26886035313001605131 + 26886035313001605095 ) } @@ -2914,7 +2916,7 @@ fn collecting_over_max_works() { who: TrancheHolderA::get(), processed_orders: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], collection: RedeemCollection { - payout_investment_redeem: 83000878263402985070, + payout_investment_redeem: 83000878263402985078, remaining_investment_redeem: 5368709120000000000 }, outcome: CollectOutcome::PartiallyCollected, @@ -2939,7 +2941,7 @@ fn collecting_over_max_works() { who: TrancheHolderA::get(), processed_orders: vec![10], collection: RedeemCollection { - payout_investment_redeem: 9984196363462686567, + payout_investment_redeem: 9984196363462686568, remaining_investment_redeem: 0 }, outcome: CollectOutcome::FullyCollected @@ -2952,7 +2954,7 @@ fn collecting_over_max_works() { ); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - 92985074626865671637 + 92985074626865671646 ) } }) From f427d381132c997fd3f19e738068a916677fa697 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 08:30:08 +0100 Subject: [PATCH 7/9] modify event index --- pallets/investments/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/investments/src/tests.rs b/pallets/investments/src/tests.rs index ab7f71ca6e..ebea7701f1 100644 --- a/pallets/investments/src/tests.rs +++ b/pallets/investments/src/tests.rs @@ -2783,7 +2783,7 @@ fn collecting_fully_works() { INVESTMENT_0_0 )); assert_eq!( - n_last_event(3), + n_last_event(4), Event::InvestCollectedWithoutActivePosition { investment_id: INVESTMENT_0_0, who: TrancheHolderC::get() From 3487a98251c9d97e064db4781054842c9ab903f5 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 15:24:39 +0100 Subject: [PATCH 8/9] fix benchmarking tests --- libs/mocks/src/pools.rs | 4 ++-- pallets/investments/src/benchmarking.rs | 12 ++++++++++++ pallets/investments/src/mock.rs | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/mocks/src/pools.rs b/libs/mocks/src/pools.rs index ba4ce059e6..3cec9b779d 100644 --- a/libs/mocks/src/pools.rs +++ b/libs/mocks/src/pools.rs @@ -26,7 +26,7 @@ pub mod pallet { type Balance; type BalanceRatio; type CurrencyId; - type TrancheCurrency; + type TrancheCurrency: Default; } #[pallet::pallet] @@ -203,7 +203,7 @@ pub mod pallet { type PoolId = T::PoolId; fn bench_default_investment_id(_: Self::PoolId) -> Self::InvestmentId { - unimplemented!(); + T::TrancheCurrency::default() } } } diff --git a/pallets/investments/src/benchmarking.rs b/pallets/investments/src/benchmarking.rs index 0cc22c0b49..280354198c 100644 --- a/pallets/investments/src/benchmarking.rs +++ b/pallets/investments/src/benchmarking.rs @@ -56,6 +56,9 @@ mod benchmarks { #[benchmark] fn update_invest_order() -> Result<(), BenchmarkError> { + #[cfg(test)] + crate::mock::configure_accountant_mock(); + let caller: T::AccountId = whitelisted_caller(); let investment_id = Helper::::get_investment_id(); let currency_id = T::Accountant::info(investment_id)?.payment_currency; @@ -70,6 +73,9 @@ mod benchmarks { #[benchmark] fn update_redeem_order() -> Result<(), BenchmarkError> { + #[cfg(test)] + crate::mock::configure_accountant_mock(); + let caller: T::AccountId = whitelisted_caller(); let investment_id = Helper::::get_investment_id(); let currency_id: CurrencyOf = investment_id.into(); @@ -84,6 +90,9 @@ mod benchmarks { #[benchmark] fn collect_investments(n: Linear<1, 10>) -> Result<(), BenchmarkError> { + #[cfg(test)] + crate::mock::configure_accountant_mock(); + let caller: T::AccountId = whitelisted_caller(); let investment_id = Helper::::get_investment_id(); let currency_id = T::Accountant::info(investment_id)?.payment_currency; @@ -110,6 +119,9 @@ mod benchmarks { #[benchmark] fn collect_redemptions(n: Linear<1, 10>) -> Result<(), BenchmarkError> { + #[cfg(test)] + crate::mock::configure_accountant_mock(); + let caller: T::AccountId = whitelisted_caller(); let investment_id = Helper::::get_investment_id(); let currency_id: CurrencyOf = investment_id.into(); diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index a696725982..92eaf6de7c 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -362,7 +362,7 @@ impl TestExternalitiesBuilder { } } -fn configure_accountant_mock() { +pub fn configure_accountant_mock() { let state = Rc::new(RefCell::new(BTreeMap::from([ ( INVESTMENT_0_0, From 46076b6723ff1930ac8c35e8b7822548cbed8742 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 14 Dec 2023 16:15:26 +0100 Subject: [PATCH 9/9] remove Default restriction for pool mocks --- libs/mocks/src/pools.rs | 13 ++++++++++--- pallets/investments/src/benchmarking.rs | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/mocks/src/pools.rs b/libs/mocks/src/pools.rs index 3cec9b779d..e5c790cc34 100644 --- a/libs/mocks/src/pools.rs +++ b/libs/mocks/src/pools.rs @@ -26,7 +26,7 @@ pub mod pallet { type Balance; type BalanceRatio; type CurrencyId; - type TrancheCurrency: Default; + type TrancheCurrency; } #[pallet::pallet] @@ -104,6 +104,13 @@ pub mod pallet { ) { register_call!(move |(a, b, c)| f(a, b, c)); } + + #[cfg(feature = "runtime-benchmarks")] + pub fn mock_bench_default_investment_id( + f: impl Fn(T::PoolId) -> T::TrancheCurrency + 'static, + ) { + register_call!(f); + } } impl PoolInspect for Pallet { @@ -202,8 +209,8 @@ pub mod pallet { type InvestmentId = T::TrancheCurrency; type PoolId = T::PoolId; - fn bench_default_investment_id(_: Self::PoolId) -> Self::InvestmentId { - T::TrancheCurrency::default() + fn bench_default_investment_id(a: Self::PoolId) -> Self::InvestmentId { + execute_call!(a) } } } diff --git a/pallets/investments/src/benchmarking.rs b/pallets/investments/src/benchmarking.rs index 280354198c..719b0ac07b 100644 --- a/pallets/investments/src/benchmarking.rs +++ b/pallets/investments/src/benchmarking.rs @@ -37,6 +37,11 @@ where let pool_id = Default::default(); let pool_admin = account("pool_admin", 0, 0); + #[cfg(test)] + crate::mock::MockAccountant::mock_bench_default_investment_id(|_| { + crate::mock::InvestmentId::default() + }); + T::Accountant::bench_create_funded_pool(pool_id, &pool_admin); T::Accountant::bench_default_investment_id(pool_id) }