From e79f3fec853ef591ec0a8838a400a2f1b940b4cb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 17 Jul 2023 16:56:16 +0200 Subject: [PATCH 01/96] feat: init pallet-foreign-investments --- Cargo.lock | 17 ++ Cargo.toml | 1 + pallets/foreign-investments/Cargo.toml | 59 ++++++ .../foreign-investments/src/benchmarking.rs | 48 +++++ pallets/foreign-investments/src/lib.rs | 184 ++++++++++++++++++ pallets/foreign-investments/src/mock.rs | 72 +++++++ pallets/foreign-investments/src/tests.rs | 40 ++++ pallets/foreign-investments/src/types.rs | 140 +++++++++++++ pallets/foreign-investments/src/weights.rs | 103 ++++++++++ 9 files changed, 664 insertions(+) create mode 100644 pallets/foreign-investments/Cargo.toml create mode 100644 pallets/foreign-investments/src/benchmarking.rs create mode 100644 pallets/foreign-investments/src/lib.rs create mode 100644 pallets/foreign-investments/src/mock.rs create mode 100644 pallets/foreign-investments/src/tests.rs create mode 100644 pallets/foreign-investments/src/types.rs create mode 100644 pallets/foreign-investments/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 581b6b3526..3b467a1d2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7316,6 +7316,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-foreign-investments" +version = "1.0.0" +dependencies = [ + "cfg-primitives", + "cfg-traits", + "cfg-types", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec 3.4.0", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-grandpa" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index f78a63d54d..581c9653ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ members = [ "pallets/crowdloan-claim", "pallets/crowdloan-reward", "pallets/fees", + "pallets/foreign-investments", "pallets/interest-accrual", "pallets/investments", "pallets/keystore", diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml new file mode 100644 index 0000000000..799a8d9be3 --- /dev/null +++ b/pallets/foreign-investments/Cargo.toml @@ -0,0 +1,59 @@ +[package] +authors = ["Centrifuge "] +description = "Pallet to enable investments and redemptions via a foreign interface" +edition = "2021" +license = "LGPL-3.0" +name = "pallet-foreign-investments" +repository = "https://github.com/centrifuge/centrifuge-chain" +version = "1.0.0" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } + +cfg-primitives = { path = "../../libs/primitives", default-features = false } +cfg-traits = { path = "../../libs/traits", default-features = false } +cfg-types = { path = "../../libs/types", default-features = false } + +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } + +# Benchmarking dependencies - optional +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } + +[dev-dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } + +[features] +default = ["std"] +std = [ + "cfg-primitives/std", + "cfg-traits/std", + "cfg-types/std", + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", +] +runtime-benchmarks = [ + "cfg-traits/runtime-benchmarks", + "cfg-types/runtime-benchmarks", + "cfg-primitives/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "cfg-primitives/try-runtime", + "cfg-traits/try-runtime", + "frame-support/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/pallets/foreign-investments/src/benchmarking.rs b/pallets/foreign-investments/src/benchmarking.rs new file mode 100644 index 0000000000..60d5e4efad --- /dev/null +++ b/pallets/foreign-investments/src/benchmarking.rs @@ -0,0 +1,48 @@ +// 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. + +// //! Benchmarking setup for pallet-template +// #![cfg(feature = "runtime-benchmarks")] +// use super::*; + +// #[allow(unused)] +// use crate::Pallet as Template; +// use frame_benchmarking::v2::*; +// use frame_system::RawOrigin; + +// #[benchmarks] +// mod benchmarks { +// use super::*; + +// #[benchmark] +// fn do_something() { +// let value = 100u32.into(); +// let caller: T::AccountId = whitelisted_caller(); +// #[extrinsic_call] +// do_something(RawOrigin::Signed(caller), value); + +// assert_eq!(Something::::get(), Some(value)); +// } + +// #[benchmark] +// fn cause_error() { +// Something::::put(100u32); +// let caller: T::AccountId = whitelisted_caller(); +// #[extrinsic_call] +// cause_error(RawOrigin::Signed(caller)); + +// assert_eq!(Something::::get(), Some(101u32)); +// } + +// impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); +// } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs new file mode 100644 index 0000000000..2aad183dfb --- /dev/null +++ b/pallets/foreign-investments/src/lib.rs @@ -0,0 +1,184 @@ +// 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. + +#![cfg_attr(not(feature = "std"), no_std)] + +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// +pub use pallet::*; + +// #[cfg(test)] +// mod mock; + +// #[cfg(test)] +// mod tests; + +// #[cfg(feature = "runtime-benchmarks")] +// mod benchmarking; +// pub mod weights; +// pub use weights::*; + +pub mod impls; +pub mod types; + +// TODO: Remove dev_mode before merging +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use cfg_traits::{InvestmentCollector, TrancheCurrency}; + use cfg_types::investments::InvestmentInfo; + use frame_support::{dispatch::HasCompact, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::AtLeast32BitUnsigned; + use types::InvestState; + + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + /// Configure the pallet by specifying the parameters and types on which it + /// depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's + /// definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Type representing the weight of this pallet + type WeightInfo: frame_system::WeightInfo; + + // TODO: Check whether we actually want something like CurrencyBalance + /// The source of truth for the balance of accounts + type Balance: Parameter + + Member + + AtLeast32BitUnsigned + + Default + + Copy + + MaybeSerializeDeserialize + + MaxEncodedLen; + + /// The currency type of transferrable tokens + type CurrencyId: Parameter + + Member + + Copy + + MaybeSerializeDeserialize + + Ord + + TypeInfo + + MaxEncodedLen; + + /// The pool id type required for the investment identifier + type PoolId: Member + + Parameter + + Default + + Copy + + HasCompact + + MaxEncodedLen + + core::fmt::Debug; + + /// The tranche id type required for the investment identifier + type TrancheId: Member + + Parameter + + Default + + Copy + + MaxEncodedLen + + TypeInfo + + From<[u8; 16]>; + + /// The investment identifying type required for the investment type + type InvestmentId: TrancheCurrency + + Into + + Clone + + Member + + Parameter + + Copy + + MaxEncodedLen; + + /// The internal investment type which handles the actual investment on + /// top of the wrapper implementation of this Pallet + type Investment: cfg_traits::Investment< + Self::AccountId, + Amount = Self::Balance, + CurrencyId = Self::CurrencyId, + Error = DispatchError, + InvestmentId = Self::InvestmentId, + > + InvestmentCollector< + Self::AccountId, + Error = DispatchError, + InvestmentId = Self::InvestmentId, + Result = (), + >; + + /// The token swap order identifying type + type TokenSwapOrderId: Parameter + + Member + + Copy + + MaybeSerializeDeserialize + + Ord + + TypeInfo + + MaxEncodedLen; + } + + /// Maps an investor and their `InvestmentId` to the corresponding + /// `InvestState`. + /// + /// NOTE: The lifetime of this storage starts with initializing a currency + /// swap into the required pool currency and ends upon fully processing the + /// investment after the potential swap. In case a swap is not required, the + /// investment starts with `InvestState::InvestmentOngoing`. + #[pallet::storage] + pub(super) type InvestmentState = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, + InvestState, + >; + + /// Maps `TokenSwapOrders` to `InvestmentInfo` to implicitly enable mapping + /// to `InvestmentState`. + /// + /// NOTE: The storage is immediately killed when the swap order is + /// completely fulfilled even if the investment might not be fully + /// processed. + #[pallet::storage] + pub(super) type ForeignInvestmentInfo = StorageMap< + _, + Blake2_128Concat, + T::TokenSwapOrderId, + InvestmentInfo, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + SomethingStored { something: u32, who: T::AccountId }, + } + + #[pallet::error] + pub enum Error { + /// Failed to retrieve the `InvestmentInfo` from the given + /// `TokenSwapOrderId`. + /// + /// NOTE: We must ensure, this can practically never happen! + InvestmentInfoNotFound, + /// Failed to determine whether the corresponding currency can be either + /// used for payment or payout of an investment. + /// + /// NOTE: We must ensure, this can practically never happen! + InvalidInvestmentCurrency, + } + + #[pallet::call] + impl Pallet {} +} diff --git a/pallets/foreign-investments/src/mock.rs b/pallets/foreign-investments/src/mock.rs new file mode 100644 index 0000000000..d847608fb4 --- /dev/null +++ b/pallets/foreign-investments/src/mock.rs @@ -0,0 +1,72 @@ +// 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 crate as pallet_template; +// use frame_support::traits::{ConstU16, ConstU64}; +// use sp_core::H256; +// use sp_runtime::{ +// testing::Header, +// traits::{BlakeTwo256, IdentityLookup}, +// }; + +// type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +// type Block = frame_system::mocking::MockBlock; + +// // Configure a mock runtime to test the pallet. +// frame_support::construct_runtime!( +// pub enum Test where +// Block = Block, +// NodeBlock = Block, +// UncheckedExtrinsic = UncheckedExtrinsic, +// { +// System: frame_system, +// TemplateModule: pallet_template, +// } +// ); + +// impl frame_system::Config for Test { +// type BaseCallFilter = frame_support::traits::Everything; +// type BlockWeights = (); +// type BlockLength = (); +// type DbWeight = (); +// type RuntimeOrigin = RuntimeOrigin; +// type RuntimeCall = RuntimeCall; +// type Index = u64; +// type BlockNumber = u64; +// type Hash = H256; +// type Hashing = BlakeTwo256; +// type AccountId = u64; +// type Lookup = IdentityLookup; +// type Header = Header; +// type RuntimeEvent = RuntimeEvent; +// type BlockHashCount = ConstU64<250>; +// type Version = (); +// type PalletInfo = PalletInfo; +// type AccountData = (); +// type OnNewAccount = (); +// type OnKilledAccount = (); +// type SystemWeightInfo = (); +// type SS58Prefix = ConstU16<42>; +// type OnSetCode = (); +// type MaxConsumers = frame_support::traits::ConstU32<16>; +// } + +// impl pallet_template::Config for Test { +// type RuntimeEvent = RuntimeEvent; +// type WeightInfo = (); +// } + +// // Build genesis storage according to the mock runtime. +// pub fn new_test_ext() -> sp_io::TestExternalities { +// frame_system::GenesisConfig::default().build_storage::().unwrap().into() +// } diff --git a/pallets/foreign-investments/src/tests.rs b/pallets/foreign-investments/src/tests.rs new file mode 100644 index 0000000000..74fc626f65 --- /dev/null +++ b/pallets/foreign-investments/src/tests.rs @@ -0,0 +1,40 @@ +// 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 crate::{mock::*, Error, Event}; +// use frame_support::{assert_noop, assert_ok}; + +// #[test] +// fn it_works_for_default_value() { +// new_test_ext().execute_with(|| { +// // Go past genesis block so events get deposited +// System::set_block_number(1); +// // Dispatch a signed extrinsic. +// assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); +// // Read pallet storage and assert an expected result. +// assert_eq!(TemplateModule::something(), Some(42)); +// // Assert that the correct event was deposited +// System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); +// }); +// } + +// #[test] +// fn correct_error_for_none_value() { +// new_test_ext().execute_with(|| { +// // Ensure the expected error is thrown when no value is present. +// assert_noop!( +// TemplateModule::cause_error(RuntimeOrigin::signed(1)), +// Error::::NoneValue +// ); +// }); +// } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs new file mode 100644 index 0000000000..ae1bdf463c --- /dev/null +++ b/pallets/foreign-investments/src/types.rs @@ -0,0 +1,140 @@ +// 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 codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +// TODO: Might want to use this trimmed down version of InvestmentInfo for the +// ForeignInvestmentInfo storage in case we don't need to store the payment +// currency +// #[derive( +// Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, +// TypeInfo, MaxEncodedLen, )] +// pub struct ForeignInvestment { +// pub investor: Balance, +// pub investment_id: InvestmentId, +// } + +#[derive( + Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] +pub struct Swap { + pub currency: Currency, + pub amount: Balance, +} + +/// Reflects all states a foreign investment can be in until it is processed. +/// This includes swapping it into a pool currency or back, if the investment is +/// decreased before it is fully processed. +#[derive( + Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] +pub enum InvestState { + #[default] + NoState, + /// The investment is waiting to be processed. + InvestmentOngoing { invest_amount: Balance }, + /// The investment is currently swapped into the required pool currency. + ActiveSwapIntoPoolCurrency(Swap), + /// The unprocessed investment was fully decreased and is currently swapped + /// back into the corresponding return currency. + ActiveSwapIntoReturnCurrency(Swap), + /// The investment is not fully swapped into pool currency and thus split + /// into two: + /// * One part is still being swapped. + /// * The other part is already waiting to be processed as investment. + ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap, + invest_amount: Balance, + }, + /// The investment is split into two: + /// * One part is waiting to be processed as investment. + /// * The other part is swapped back into the return currency as a + /// result of decreasing the invested amount before being processed. + ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap: Swap, + invest_amount: Balance, + }, + /// The investment is split into two: + /// * The one part is swapping into pool currency. + /// * The other part was swapped back into the return currency as a + /// result of decreasing the invested amount before being processed. + /// + /// NOTE: This state can be transitioned into `ActiveSwapIntoPoolCurrency` + /// by applying the corresponding trigger to handle the return amount. + ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + swap: Swap, + done_amount: Balance, + }, + /// The investment is swapped back into the return currency and was already + /// partially fulfilled. + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap, + done_amount: Balance, + }, + /// The investment is split into three: + /// * One part is currently swapping into the pool currency. + /// * The second part is already waiting to be processed as investment. + /// * The remaining part was swapped back into the return currency as a + /// result of decreasing the invested amount before being processed. + /// + /// NOTE: This state can be transitioned into + /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` by applying the + /// corresponding trigger to handle the return amount. + ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap, + done_amount: Balance, + invest_amount: Balance, + }, + /// The investment is split into three: + /// * One is waiting to be processed as investment. + /// * The second part is swapped back into the return currency as a + /// result of decreasing the invested amount before being processed. + /// * The remaining part was already swapped back into the return + /// currency. + /// + /// NOTE: This state should not be transitioned by applying the trigger for + /// the done part but wait until the active swap is fulfilled. + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap, + done_amount: Balance, + invest_amount: Balance, + }, + // TODO: Maybe remove + /// The unprocessed investment was swapped back into return currency. + /// + /// NOTE: This state can be killed by applying the corresponding trigger to + /// handle the return amount. + SwapIntoReturnDone(Swap), + // TODO: Maybe remove + /// The investment is split into two: + /// * One part is waiting to be processed as an investment + /// * The swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. + /// + /// NOTE: This state can be transitioned into `InvestmentOngoing` by + /// applying the corresponding trigger to handle the return amount. + SwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap, + invest_amount: Balance, + }, +} + +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +// TODO: Complete +pub enum InvestTransition { + IncreaseInvestOrder(Swap), + DecreaseInvestOrder(Swap), + SwapIntoPool(Swap), + SwapIntoReturn(Swap), +} diff --git a/pallets/foreign-investments/src/weights.rs b/pallets/foreign-investments/src/weights.rs new file mode 100644 index 0000000000..f309c029a3 --- /dev/null +++ b/pallets/foreign-investments/src/weights.rs @@ -0,0 +1,103 @@ +// 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. + +// //! Autogenerated weights for pallet_template +// //! +// //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +// //! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +// //! WORST CASE MAP SIZE: `1000000` +// //! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `` +// //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// // Executed Command: +// // ../../target/release/node-template +// // benchmark +// // pallet +// // --chain +// // dev +// // --pallet +// // pallet_template +// // --extrinsic +// // * +// // --steps=50 +// // --repeat=20 +// // --execution=wasm +// // --wasm-execution=compiled +// // --output +// // pallets/template/src/weights.rs +// // --template +// // ../../.maintain/frame-weight-template.hbs + +// #![cfg_attr(rustfmt, rustfmt_skip)] +// #![allow(unused_parens)] +// #![allow(unused_imports)] + +// use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +// use core::marker::PhantomData; + +// /// Weight functions needed for pallet_template. +// pub trait WeightInfo { +// fn do_something() -> Weight; +// fn cause_error() -> Weight; +// } + +// /// Weights for pallet_template using the Substrate node and recommended hardware. +// pub struct SubstrateWeight(PhantomData); +// impl WeightInfo for SubstrateWeight { +// /// Storage: TemplateModule Something (r:0 w:1) +// /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) +// fn do_something() -> Weight { +// // Proof Size summary in bytes: +// // Measured: `0` +// // Estimated: `0` +// // Minimum execution time: 8_000_000 picoseconds. +// Weight::from_parts(9_000_000, 0) +// .saturating_add(T::DbWeight::get().writes(1_u64)) +// } +// /// Storage: TemplateModule Something (r:1 w:1) +// /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) +// fn cause_error() -> Weight { +// // Proof Size summary in bytes: +// // Measured: `32` +// // Estimated: `1489` +// // Minimum execution time: 6_000_000 picoseconds. +// Weight::from_parts(6_000_000, 1489) +// .saturating_add(T::DbWeight::get().reads(1_u64)) +// .saturating_add(T::DbWeight::get().writes(1_u64)) +// } +// } + +// // For backwards compatibility and tests +// impl WeightInfo for () { +// /// Storage: TemplateModule Something (r:0 w:1) +// /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) +// fn do_something() -> Weight { +// // Proof Size summary in bytes: +// // Measured: `0` +// // Estimated: `0` +// // Minimum execution time: 8_000_000 picoseconds. +// Weight::from_parts(9_000_000, 0) +// .saturating_add(RocksDbWeight::get().writes(1_u64)) +// } +// /// Storage: TemplateModule Something (r:1 w:1) +// /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) +// fn cause_error() -> Weight { +// // Proof Size summary in bytes: +// // Measured: `32` +// // Estimated: `1489` +// // Minimum execution time: 6_000_000 picoseconds. +// Weight::from_parts(6_000_000, 1489) +// .saturating_add(RocksDbWeight::get().reads(1_u64)) +// .saturating_add(RocksDbWeight::get().writes(1_u64)) +// } +// } From aa2b6adb4d578a409ecff3cbd4f7676dc1201b97 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 17 Jul 2023 16:57:24 +0200 Subject: [PATCH 02/96] wip: SwapNotificationHandler, ForeignInvestment traits --- libs/traits/src/lib.rs | 89 +++++++++ pallets/connectors/src/lib.rs | 1 + pallets/foreign-investments/src/impls.rs | 240 +++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 pallets/foreign-investments/src/impls.rs diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index d1fe42e651..82319389f7 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -685,3 +685,92 @@ pub trait CurrencyInspect { /// Checks whether the provided currency is a tranche token. fn is_tranche_token(currency: Self::CurrencyId) -> bool; } + +trait TokenSwaps { + type CurrencyId; + type Balance; + type OrderId; + + /// Swap tokens buying a `buy_amount` of `currency_in` using the + /// `currency_out` tokens. The implementor of this method should know the + /// current market rate between those two currencies. `sell_price_limit` + /// defines the lowest price acceptable for `currency_in` currency when + /// buying with `currency_out`. This protects order placer if market changes + /// unfavorably for swap order. Returns the order id created with by this + /// buy order if it could not be immediately and completely fulfilled. + /// If there was already an active order with the same account currencies, + /// the order is increased/decreased and the same order id is returned. + fn place_order( + account: AccountId, + currency_out: Self::CurrencyId, + currency_in: Self::CurrencyId, + buy_amount: Self::Balance, + sell_price_limit: Self::Balance, + min_fulfillment_amount: Self::Balance, + ) -> Result; + + /// Can fail for various reasons + /// + /// E.g. min_fulfillment_amount is lower and + /// the system has already fulfilled up to the previous + /// one. + fn update_order( + account: AccountId, + order_id: Self::OrderId, + buy_amount: Self::Balance, + sell_price_limit: Self::Balance, + min_fulfillment_amount: Self::Balance, + ) -> DispatchResult; + + /// Cancel an already active order. + fn cancel_order(order: Self::OrderId); + + /// Check if the order is still active. + fn is_active(order: Self::OrderId) -> bool; +} + +pub trait ForeignInvestment { + type Amount; + type CurrencyId; + type Error: Debug; + type InvestmentId; + + type SwapNotification; + + // type Investment: Investment< + // AccountId, + // Amount = Self::Amount, + // CurrencyId = Self::CurrencyId, + // Error = Self::Error, + // InvestmentId = Self::InvestmentId, + // >; + + /// * Apply state transition + /// * Kick off swap + fn update_foreign_invest_order( + who: &AccountId, + payment_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + // Do actual investment update after successful (partial) token swap + // * Triggered by SwapNotification + // fn finalize_update_investment( + // who: &AccountId, + // investment_id: Self::InvestmentId, + // amount: Self::Amount, + // ) -> Result<(), Self::Error>; +} + +pub trait SwapNotificationHandler { + /// The identifying type + type Id; + /// The type for possible states + type Status; + /// The error type + type Error: Debug; + + /// Notify that the status has changed for the given id + fn notify_status_change(id: Self::Id, status: Self::Status) -> Result<(), Self::Error>; +} diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index e249473c47..9d65bd1284 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -224,6 +224,7 @@ pub mod pallet { + MaxEncodedLen + TryInto, Error = DispatchError> + TryFrom, Error = DispatchError> + // Enables checking whether currency is tranche token + CurrencyInspect>; /// The converter from a DomainAddress to a Substrate AccountId. diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs new file mode 100644 index 0000000000..eb4ab7b566 --- /dev/null +++ b/pallets/foreign-investments/src/impls.rs @@ -0,0 +1,240 @@ +// 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 cfg_traits::{ForeignInvestment, Investment, SwapNotificationHandler}; +use cfg_types::investments::InvestmentInfo; +use sp_runtime::DispatchError; + +use crate::{ + pallet, + types::{InvestState, InvestTransition, Swap}, + Config, Error, ForeignInvestmentInfo, InvestmentState, Pallet, +}; + +impl SwapNotificationHandler for Pallet { + type Error = DispatchError; + type Id = T::TokenSwapOrderId; + type Status = T::Balance; + + fn notify_status_change( + id: T::TokenSwapOrderId, + status: T::Balance, + ) -> Result<(), DispatchError> { + // get InvestState + let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; + + // update invest state + let pre_state = InvestmentState::::get(info.owner, info.id).unwrap_or_default(); + + match info.payment_currency { + pool_currency if T::Investment::accepted_payment_currency(info.id, pool_currency) => { + pre_state + .transition(InvestTransition::SwapIntoPool(Swap { + currency: pool_currency, + amount: status, + })) + .map(|_| ()) + } + return_currency + if T::Investment::accepted_payout_currency(info.id, return_currency) => + { + pre_state + .transition(InvestTransition::SwapIntoReturn(Swap { + currency: return_currency, + amount: status, + })) + .map(|_| ()) + } + _ => Err(Error::::InvalidInvestmentCurrency.into()), + } + } +} + +impl ForeignInvestment for Pallet { + type Amount = T::Balance; + type CurrencyId = T::CurrencyId; + type Error = DispatchError; + type InvestmentId = T::InvestmentId; + type SwapNotification = Pallet; + + fn update_foreign_invest_order( + who: &T::AccountId, + payment_currency: T::CurrencyId, + investment_id: T::InvestmentId, + amount: T::Balance, + ) -> Result<(), DispatchError> { + let pre_amount = T::Investment::investment(who, investment_id.clone())?; + let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + let swap = Swap { + currency: payment_currency, + amount, + }; + + if amount > pre_amount { + let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(swap))?; + Ok(()) + } else if amount < pre_amount { + let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(swap))?; + Ok(()) + } else { + Ok(()) + } + } +} + +impl InvestState +where + Balance: Clone, + Currency: Clone, +{ + // TODO: Kill storage here if post_state = NoState? Might need a wrapper around + // this to mutate the actual storage + /// Apply state machine, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram + pub fn transition( + &self, + transition: InvestTransition, + ) -> Result { + match transition { + InvestTransition::IncreaseInvestOrder(swap) => { + Self::handle_increase(&self, swap.currency, swap.amount) + } + InvestTransition::DecreaseInvestOrder(swap) => { + Self::handle_decrease(&self, swap.currency, swap.amount) + } + InvestTransition::SwapIntoPool(swap) => { + Self::handle_fulfilled_swap_into_pool(&self, swap.currency, swap.amount) + } + // TODO: Should expose NotificationHandler implemented by consumers such as Connectors + // for handling `ExecutedDecreaseInvestOrder`. + InvestTransition::SwapIntoReturn(swap) => { + Self::handle_fulfilled_swap_into_return(&self, swap.currency, swap.amount) + } + } + } +} + +// Actual impl of transition +impl InvestState +where + Balance: Clone, + Currency: Clone, +{ + /// Handle `increase` transitions. + fn handle_increase( + &self, + swap_currency: Currency, + amount: Balance, + ) -> Result { + todo!("Do state transition here") + } + + /// Handle `decrease` transitions. + fn handle_decrease( + &self, + swap_currency: Currency, + amount: Balance, + ) -> Result { + todo!("Do state transition here") + } + + /// Handle partial/full token swap order transitions into pool currency. + /// These should always increase the active ongoing investment. + fn handle_fulfilled_swap_into_pool( + &self, + swap_currency: Currency, + amount: Balance, + ) -> Result { + todo!("Do state transition here") + } + + /// Handle partial/full token swap order transitions into return currency. + /// Assumes the corresponding investment has been decreased beforehand. + fn handle_fulfilled_swap_into_return( + &self, + swap_currency: Currency, + amount: Balance, + ) -> Result { + todo!("Do state transition here") + } +} + +// TODO: How to merge token swaps and investment trait? Create new trait +// ForeignInvestment? > Check diagrams + +// impl Investment for Pallet { +// type Amount = T::Balance; +// type CurrencyId = T::CurrencyId; +// type Error = DispatchError; +// type InvestmentId = T::InvestmentId; + +// fn update_investment( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// amount: Self::Amount, +// ) -> Result<(), Self::Error> { +// let pre_amount = Self::investment(who, investment_id.clone())?; +// let pre_state = InvestmentState::::get(who, +// investment_id.clone()).unwrap_or_default(); + +// if amount > pre_amount { +// // TODO: Can payment currency be derived? +// let swap_currency = +// ::info(investment_id).map(|info| +// info.payment_currency()); let post_state: Option::Balance, ::CurrencyId>> = pre_state. +// transition(InvestTransition::IncreaseInvestOrder(amount))?; Ok(()) +// } else if amount < pre_amount { +// let post_state: Option::Balance, ::CurrencyId>> = pre_state. +// transition(InvestTransition::DecreaseInvestOrder(amount))?; Ok(()) +// } else { +// Ok(()) +// } +// } + +// fn accepted_payment_currency( +// investment_id: Self::InvestmentId, +// currency: Self::CurrencyId, +// ) -> bool { +// T::Investment::accepted_payment_currency(investment_id, currency) +// } + +// fn investment( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// ) -> Result { +// todo!() +// } + +// fn update_redemption( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// amount: Self::Amount, +// ) -> Result<(), Self::Error> { +// todo!() +// } + +// fn accepted_payout_currency( +// investment_id: Self::InvestmentId, +// currency: Self::CurrencyId, +// ) -> bool { +// T::Investment::accepted_payout_currency(investment_id, currency) +// } + +// fn redemption( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// ) -> Result { +// todo!() +// } +// } From 79edb72ec979319dbfad79d9e2a9f32048510b21 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 17 Jul 2023 17:11:38 +0200 Subject: [PATCH 03/96] docs: some comments --- libs/traits/src/lib.rs | 2 +- pallets/foreign-investments/src/impls.rs | 35 ++++++++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 82319389f7..ce7e1ed6ea 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -763,7 +763,7 @@ pub trait ForeignInvestment { // ) -> Result<(), Self::Error>; } -pub trait SwapNotificationHandler { +pub trait SwapNotificationHook { /// The identifying type type Id; /// The type for possible states diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index eb4ab7b566..eb59b53086 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -11,7 +11,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Investment, SwapNotificationHandler}; +use cfg_traits::{ForeignInvestment, Investment, SwapNotificationHook}; use cfg_types::investments::InvestmentInfo; use sp_runtime::DispatchError; @@ -21,7 +21,11 @@ use crate::{ Config, Error, ForeignInvestmentInfo, InvestmentState, Pallet, }; -impl SwapNotificationHandler for Pallet { +// Handles the second stage of updating investments. Whichever (potentially +// async) code path of the first stage concludes it (partially) should call +// `Swap::Config::SwapNotificationHandler::notify_status_update(swap_order_id, +// swapped_amount)`. +impl SwapNotificationHook for Pallet { type Error = DispatchError; type Id = T::TokenSwapOrderId; type Status = T::Balance; @@ -67,6 +71,10 @@ impl ForeignInvestment for Pallet { type InvestmentId = T::InvestmentId; type SwapNotification = Pallet; + // Consumers such as Connectors should call this function instead of + // `Investment::update_invest_order` as this implementation accounts for + // (potentially) splitting the update into two stages. The second stage is + // resolved by `SwapNotificationHook::notify_status_change`. fn update_foreign_invest_order( who: &T::AccountId, payment_currency: T::CurrencyId, @@ -114,7 +122,7 @@ where InvestTransition::SwapIntoPool(swap) => { Self::handle_fulfilled_swap_into_pool(&self, swap.currency, swap.amount) } - // TODO: Should expose NotificationHandler implemented by consumers such as Connectors + // TODO: Should expose hook implemented by consumers such as Connectors // for handling `ExecutedDecreaseInvestOrder`. InvestTransition::SwapIntoReturn(swap) => { Self::handle_fulfilled_swap_into_return(&self, swap.currency, swap.amount) @@ -129,7 +137,8 @@ where Balance: Clone, Currency: Clone, { - /// Handle `increase` transitions. + /// Handle `increase` transitions depicted by `msg::increase` edges in the + /// state diagram. fn handle_increase( &self, swap_currency: Currency, @@ -138,7 +147,8 @@ where todo!("Do state transition here") } - /// Handle `decrease` transitions. + /// Handle `decrease` transitions depicted by `msg::decrease` edges in the + /// state diagram. fn handle_decrease( &self, swap_currency: Currency, @@ -147,8 +157,11 @@ where todo!("Do state transition here") } - /// Handle partial/full token swap order transitions into pool currency. - /// These should always increase the active ongoing investment. + /// Handle partial/full token swap order transitions into pool currency + /// depicted by `order_partial` edges in the state diagram where the swap + /// currency matches the pool one. + /// + /// NOTE: These should always increase the active ongoing investment. fn handle_fulfilled_swap_into_pool( &self, swap_currency: Currency, @@ -157,8 +170,12 @@ where todo!("Do state transition here") } - /// Handle partial/full token swap order transitions into return currency. - /// Assumes the corresponding investment has been decreased beforehand. + /// Handle partial/full token swap order transitions into return currency + /// depicted by `order_partial` edges in the state diagram with the swap + /// currency matches the return one. + /// + /// NOTE: Assumes the corresponding investment has been decreased + /// beforehand. fn handle_fulfilled_swap_into_return( &self, swap_currency: Currency, From ee609c3a62339e381ff4f191f6e895490ca546e1 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 18 Jul 2023 15:56:58 +0200 Subject: [PATCH 04/96] wip: storage updates, hooks --- libs/traits/src/lib.rs | 7 +- libs/types/src/investments.rs | 30 ++- pallets/connectors/src/inbound.rs | 20 +- pallets/foreign-investments/src/impls.rs | 307 ++++++++++++++++++----- pallets/foreign-investments/src/lib.rs | 73 +++++- pallets/foreign-investments/src/types.rs | 14 +- 6 files changed, 376 insertions(+), 75 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index ce7e1ed6ea..5b4de44fb8 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -686,7 +686,7 @@ pub trait CurrencyInspect { fn is_tranche_token(currency: Self::CurrencyId) -> bool; } -trait TokenSwaps { +pub trait TokenSwaps { type CurrencyId; type Balance; type OrderId; @@ -749,7 +749,8 @@ pub trait ForeignInvestment { /// * Kick off swap fn update_foreign_invest_order( who: &AccountId, - payment_currency: Self::CurrencyId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, amount: Self::Amount, ) -> Result<(), Self::Error>; @@ -763,7 +764,7 @@ pub trait ForeignInvestment { // ) -> Result<(), Self::Error>; } -pub trait SwapNotificationHook { +pub trait StatusNotificationHook { /// The identifying type type Id; /// The type for possible states diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 58e50be776..a5051d0ecc 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -11,7 +11,7 @@ // GNU General Public License for more details. use cfg_traits::InvestmentProperties; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; use sp_std::cmp::PartialEq; @@ -52,3 +52,31 @@ where self.payment_currency.clone() } } + +/// A representation of an investment identifier and the corresponding owner. +/// +/// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] + +pub struct ForeignInvestmentInfo { + pub owner: AccountId, + pub id: InvestmentId, +} + +/// A representation of an executed decreased investment or redemption. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] + +pub struct ExecutedDecrease { + pub amount_payout: Balance, + pub amount_remaining: Balance, +} + +/// A representation of an executed collected investment or redemption. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] + +pub struct ExecutedCollect { + pub currency: Currency, + pub amount_currency_payout: Balance, + pub amount_tranche_tokens_payout: Balance, + pub amount_remaining: Balance, +} diff --git a/pallets/connectors/src/inbound.rs b/pallets/connectors/src/inbound.rs index ea13883b71..7feed8157d 100644 --- a/pallets/connectors/src/inbound.rs +++ b/pallets/connectors/src/inbound.rs @@ -131,13 +131,15 @@ impl Pallet { T::ForeignInvestment::update_investment(&investor, invest_id, post_amount)?; - // TODO(subsequent PR): Handle response `ExecutedDecreaseInvestOrder` message to + // TODO: Handle response `ExecutedDecreaseInvestOrder` message to // source destination which should refund the decreased amount. This includes // burning it from the investor account. // // NOTES: // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 // * Should be handled by `pallet-foreign-investments` + // * Requires notification of `currency_payout` and `remaining_invest_order` + // balances Ok(()) } @@ -203,7 +205,7 @@ impl Pallet { T::ForeignInvestment::update_redemption(&investor, invest_id, post_amount)?; - // TODO(subsequent PR): Handle response `ExecutedDecreaseRedemption` message to + // TODO: Handle response `ExecutedDecreaseRedemption` message to // source destination which should refund the decreased amount. This includes // transferring the amount from the investor to the domain locator account of // the origination domain. @@ -211,6 +213,8 @@ impl Pallet { // NOTES: // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 // * Should be handled by `pallet-foreign-investments` + // * Requires notification of `tranche_tokens_payout` and + // `remaining_redeem_order` balances Ok(()) } @@ -227,8 +231,12 @@ impl Pallet { T::ForeignInvestment::collect_investment(investor, invest_id)?; - // TODO(subsequent PR): Handle response `ExecutedCollectInvest` message to + // TODO: Handle response `ExecutedCollectInvest` message to // source destination. + // + // Requires notification of `currency_payout`, `tranche_tokens_payout` and + // `remaining_invest_order` balances as well as the payout currency id, which + // needs to be mapped to its general index. Ok(()) } @@ -245,8 +253,12 @@ impl Pallet { T::ForeignInvestment::collect_redemption(investor, invest_id)?; - // TODO(subsequent PR): Handle response `ExecutedCollectRedeem` message to + // TODO: Handle response `ExecutedCollectRedeem` message to // source destination. + // + // Requires notification of `currency_payout`, `tranche_tokens_payout` and + // `remaining_redeem_order` balances as well as the payout currency id, which + // needs to be mapped to its general index. Ok(()) } diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index eb59b53086..1de907dc13 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -11,52 +11,48 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Investment, SwapNotificationHook}; -use cfg_types::investments::InvestmentInfo; -use sp_runtime::DispatchError; +use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; +use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; +use frame_support::{traits::Get, transactional}; +use sp_runtime::{ + traits::{EnsureAdd, Zero}, + DispatchError, DispatchResult, +}; use crate::{ pallet, types::{InvestState, InvestTransition, Swap}, - Config, Error, ForeignInvestmentInfo, InvestmentState, Pallet, + Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, SwapOf, + TokenSwapOrderIds, }; // Handles the second stage of updating investments. Whichever (potentially // async) code path of the first stage concludes it (partially) should call // `Swap::Config::SwapNotificationHandler::notify_status_update(swap_order_id, // swapped_amount)`. -impl SwapNotificationHook for Pallet { +impl StatusNotificationHook for Pallet { type Error = DispatchError; type Id = T::TokenSwapOrderId; - type Status = T::Balance; + type Status = SwapOf; fn notify_status_change( id: T::TokenSwapOrderId, - status: T::Balance, + status: SwapOf, ) -> Result<(), DispatchError> { - // get InvestState let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; - - // update invest state let pre_state = InvestmentState::::get(info.owner, info.id).unwrap_or_default(); - match info.payment_currency { + match status.currency_in { pool_currency if T::Investment::accepted_payment_currency(info.id, pool_currency) => { pre_state - .transition(InvestTransition::SwapIntoPool(Swap { - currency: pool_currency, - amount: status, - })) + .transition(InvestTransition::SwapIntoPool(status)) .map(|_| ()) } return_currency if T::Investment::accepted_payout_currency(info.id, return_currency) => { pre_state - .transition(InvestTransition::SwapIntoReturn(Swap { - currency: return_currency, - amount: status, - })) + .transition(InvestTransition::SwapIntoReturn(status)) .map(|_| ()) } _ => Err(Error::::InvalidInvestmentCurrency.into()), @@ -74,25 +70,30 @@ impl ForeignInvestment for Pallet { // Consumers such as Connectors should call this function instead of // `Investment::update_invest_order` as this implementation accounts for // (potentially) splitting the update into two stages. The second stage is - // resolved by `SwapNotificationHook::notify_status_change`. + // resolved by `StatusNotificationHook::notify_status_change`. fn update_foreign_invest_order( who: &T::AccountId, - payment_currency: T::CurrencyId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, investment_id: T::InvestmentId, amount: T::Balance, ) -> Result<(), DispatchError> { let pre_amount = T::Investment::investment(who, investment_id.clone())?; let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); - let swap = Swap { - currency: payment_currency, - amount, - }; if amount > pre_amount { - let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(swap))?; + let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + amount, + }))?; Ok(()) } else if amount < pre_amount { - let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(swap))?; + let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { + currency_in: return_currency, + currency_out: pool_currency, + amount, + }))?; Ok(()) } else { Ok(()) @@ -100,32 +101,169 @@ impl ForeignInvestment for Pallet { } } +impl Pallet { + /// Updates chain storage after applying state transition of `InvestState` + /// and execute `ExecutedDecreaseHook`. + #[transactional] + fn apply_state_transition( + who: &T::AccountId, + investment_id: T::InvestmentId, + state: InvestState, + ) -> DispatchResult { + match state.clone() { + InvestState::NoState => { + Self::kill_swap_order(who, investment_id)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + + // Exit early to prevent setting InvestmentState to `NoState` + InvestmentState::::remove(who, investment_id); + return Ok(()); + }, + InvestState::InvestmentOngoing { invest_amount } => { + Self::kill_swap_order(who, investment_id)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + }, + InvestState::ActiveSwapIntoPoolCurrency(swap) | + InvestState::ActiveSwapIntoReturnCurrency(swap) | + // We don't care about `done_amount` until swap into return is fulfilled + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { + Self::place_swap_order(who, investment_id, swap)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + }, + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | + // We don't care about `done_amount` until swap into return is fulfilled + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount, .. } => { + Self::place_swap_order(who, investment_id, swap)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + }, + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + Self::place_swap_order(who, investment_id, swap)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + + // + Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + }, + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { + Self::place_swap_order(who, investment_id, swap)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + + Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + + }, + InvestState::SwapIntoReturnDone(_swap) => { + Self::kill_swap_order(who, investment_id)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + }, + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount } => { + Self::kill_swap_order(who, investment_id)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + }, + }; + + InvestmentState::::insert(who, investment_id, state); + + // TODO: Emit event? + + Ok(()) + } + + /// Kills all storage associated with token swaps and cancels the + /// potentially active swap order. + fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { + if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { + T::TokenSwaps::cancel_order(swap_order_id); + ForeignInvestmentInfo::::remove(swap_order_id); + } + Ok(()) + } + + /// Initializes or updates an existing swap order. + /// + /// Sets up `TokenSwapOrderIds` and `ForeignInvestmentInfo` storages, if the + /// order does not exist yet. + fn place_swap_order( + who: &T::AccountId, + investment_id: T::InvestmentId, + swap: SwapOf, + ) -> DispatchResult { + if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { + T::TokenSwaps::update_order( + who.clone(), + swap_order_id, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + ) + } else { + // TODO: How to handle potential failure? + let order_id = T::TokenSwaps::place_order( + who.clone(), + swap.currency_out, + swap.currency_in, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + )?; + TokenSwapOrderIds::::insert(who, investment_id, order_id); + ForeignInvestmentInfo::::insert( + order_id, + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ); + Ok(()) + } + } + + /// Sends `ExecutedDecreaseHook` notification such that any potential + /// consumer could act upon that, e.g. Connectors for + /// `ExecutedDecrease{Invest, Redeem}Order`. + fn send_executed_decrease_hook( + who: &T::AccountId, + investment_id: T::InvestmentId, + amount_payout: T::Balance, + ) -> DispatchResult { + // TODO(@mustermeiszer): Does this return the entire desired amount or do we + // need to tap into collecting? + let amount_remaining = T::Investment::investment(who, investment_id)?; + + // TODO(@mustermeiszer): Do we add the active swap amount? + T::ExecutedDecreaseHook::notify_status_change( + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ExecutedDecrease { + amount_payout, + amount_remaining, + }, + ) + } +} + impl InvestState where - Balance: Clone, - Currency: Clone, + Balance: Clone + Copy + EnsureAdd, + Currency: Clone + PartialEq, { - // TODO: Kill storage here if post_state = NoState? Might need a wrapper around - // this to mutate the actual storage - /// Apply state machine, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram + /// Solely apply state machine to transition one `InvestState` into another + /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. + /// + /// NOTE: Does not mutate storage which is done by `apply_state_transition`. pub fn transition( &self, transition: InvestTransition, ) -> Result { match transition { - InvestTransition::IncreaseInvestOrder(swap) => { - Self::handle_increase(&self, swap.currency, swap.amount) - } - InvestTransition::DecreaseInvestOrder(swap) => { - Self::handle_decrease(&self, swap.currency, swap.amount) - } + InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(&self, swap), + InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(&self, swap), InvestTransition::SwapIntoPool(swap) => { - Self::handle_fulfilled_swap_into_pool(&self, swap.currency, swap.amount) + Self::handle_fulfilled_swap_into_pool(&self, swap) } - // TODO: Should expose hook implemented by consumers such as Connectors - // for handling `ExecutedDecreaseInvestOrder`. InvestTransition::SwapIntoReturn(swap) => { - Self::handle_fulfilled_swap_into_return(&self, swap.currency, swap.amount) + Self::handle_fulfilled_swap_into_return(&self, swap) } } } @@ -134,26 +272,79 @@ where // Actual impl of transition impl InvestState where - Balance: Clone, - Currency: Clone, + Balance: Clone + Copy + EnsureAdd, + Currency: Clone + PartialEq, { + // fn swap_required(&self, + // return_currency: Currency, + // pool_currency: Currency, + // amount: Balance + // ) -> Result { + // if return_currency == pool_currency { + + // } + // } + /// Handle `increase` transitions depicted by `msg::increase` edges in the /// state diagram. - fn handle_increase( - &self, - swap_currency: Currency, - amount: Balance, - ) -> Result { - todo!("Do state transition here") + fn handle_increase(&self, swap: Swap) -> Result { + match &self { + Self::NoState => { + if swap.currency_in == swap.currency_out { + Ok(Self::InvestmentOngoing { + invest_amount: swap.amount, + }) + } else { + Ok(Self::ActiveSwapIntoPoolCurrency(swap)) + } + } + Self::InvestmentOngoing { invest_amount } => { + if swap.currency_in == swap.currency_out { + Ok(Self::InvestmentOngoing { + invest_amount: invest_amount.ensure_add(swap.amount)?, + }) + } else { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap, + invest_amount: *invest_amount, + }) + } + } + Self::ActiveSwapIntoPoolCurrency(_) => todo!(), + Self::ActiveSwapIntoReturnCurrency(_) => todo!(), + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap, + invest_amount, + } => todo!(), + Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap, + invest_amount, + } => todo!(), + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => todo!(), + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + todo!() + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount, + } => todo!(), + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount, + } => todo!(), + Self::SwapIntoReturnDone(_) => todo!(), + Self::SwapIntoReturnDoneAndInvestmentOngoing { + swap, + invest_amount, + } => todo!(), + } } /// Handle `decrease` transitions depicted by `msg::decrease` edges in the /// state diagram. - fn handle_decrease( - &self, - swap_currency: Currency, - amount: Balance, - ) -> Result { + fn handle_decrease(&self, swap: Swap) -> Result { todo!("Do state transition here") } @@ -164,8 +355,7 @@ where /// NOTE: These should always increase the active ongoing investment. fn handle_fulfilled_swap_into_pool( &self, - swap_currency: Currency, - amount: Balance, + swap: Swap, ) -> Result { todo!("Do state transition here") } @@ -178,8 +368,7 @@ where /// beforehand. fn handle_fulfilled_swap_into_return( &self, - swap_currency: Currency, - amount: Balance, + swap: Swap, ) -> Result { todo!("Do state transition here") } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 2aad183dfb..2f3eb61ea0 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -28,15 +28,22 @@ pub use pallet::*; // mod benchmarking; // pub mod weights; // pub use weights::*; +use crate::types::Swap; pub mod impls; pub mod types; +pub type SwapOf = Swap<::Balance, ::CurrencyId>; +pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentInfo< + ::AccountId, + ::InvestmentId, +>; + // TODO: Remove dev_mode before merging #[frame_support::pallet(dev_mode)] pub mod pallet { - use cfg_traits::{InvestmentCollector, TrancheCurrency}; - use cfg_types::investments::InvestmentInfo; + use cfg_traits::{InvestmentCollector, StatusNotificationHook, TokenSwaps, TrancheCurrency}; + use cfg_types::investments::{ExecutedCollect, ExecutedDecrease}; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; @@ -118,6 +125,27 @@ pub mod pallet { Result = (), >; + /// The default sell price limit for token swaps which defines the + /// lowest acceptable buy price. + /// + /// TODO(@review): Since we will only support stable coins from the + /// beginning, a global default value could be feasible or do we want to + /// have better granularity? + /// + /// NOTE: Can be removed once we implement a + /// more sophisticated swap price discovery. + type DefaultTokenSwapSellPriceLimit: Get; + + /// The default minimum fulfillment amount for token swaps. + /// + /// TODO(@review): Since we will only support stable coins from the + /// beginning, a global default value could be feasible or do we want to + /// have better granularity? + /// + /// NOTE: Can be removed once we implement a more sophisticated swap + /// price discovery. + type DefaultTokenMinFulfillmentAmount: Get; + /// The token swap order identifying type type TokenSwapOrderId: Parameter + Member @@ -126,6 +154,29 @@ pub mod pallet { + Ord + TypeInfo + MaxEncodedLen; + + /// The type which exposes token swap order functionality such as + /// placing and cancelling orders + type TokenSwaps: TokenSwaps< + Self::AccountId, + CurrencyId = Self::CurrencyId, + Balance = Self::Balance, + OrderId = Self::TokenSwapOrderId, + >; + + type ExecutedDecreaseHook: StatusNotificationHook< + Id = ForeignInvestmentInfoOf, + // TODO: Move to type + Status = ExecutedDecrease, + Error = DispatchError, + >; + + type ExecutedCollectHook: StatusNotificationHook< + Id = ForeignInvestmentInfoOf, + // TODO: Convert to type + Status = ExecutedCollect, + Error = DispatchError, + >; } /// Maps an investor and their `InvestmentId` to the corresponding @@ -148,15 +199,29 @@ pub mod pallet { /// Maps `TokenSwapOrders` to `InvestmentInfo` to implicitly enable mapping /// to `InvestmentState`. /// + /// NOTE: Here, the `payment_currency` refers to the `pool_currency`. + /// /// NOTE: The storage is immediately killed when the swap order is /// completely fulfilled even if the investment might not be fully /// processed. #[pallet::storage] - pub(super) type ForeignInvestmentInfo = StorageMap< + pub(super) type ForeignInvestmentInfo = + StorageMap<_, Blake2_128Concat, T::TokenSwapOrderId, ForeignInvestmentInfoOf>; + + /// Maps an investor and their `InvestmentId` to the corresponding + /// `TokenSwapOrderId`. + /// + /// NOTE: The storage is immediately killed when the swap order is + /// completely fulfilled even if the investment might not be fully + /// processed. + #[pallet::storage] + pub(super) type TokenSwapOrderIds = StorageDoubleMap< _, Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, T::TokenSwapOrderId, - InvestmentInfo, >; #[pallet::event] diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index ae1bdf463c..832566d122 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -13,6 +13,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_runtime::traits::EnsureAdd; // TODO: Might want to use this trimmed down version of InvestmentInfo for the // ForeignInvestmentInfo storage in case we don't need to store the payment @@ -28,8 +29,9 @@ use scale_info::TypeInfo; #[derive( Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] -pub struct Swap { - pub currency: Currency, +pub struct Swap { + pub currency_in: Currency, + pub currency_out: Currency, pub amount: Balance, } @@ -39,7 +41,7 @@ pub struct Swap { #[derive( Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] -pub enum InvestState { +pub enum InvestState { #[default] NoState, /// The investment is waiting to be processed. @@ -132,9 +134,13 @@ pub enum InvestState { #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] // TODO: Complete -pub enum InvestTransition { +pub enum InvestTransition { + /// NOTE: Assumes `swap.currency_in` is pool currency IncreaseInvestOrder(Swap), + /// NOTE: Assumes `swap.currency_in` is return currency DecreaseInvestOrder(Swap), + /// NOTE: Assumes `swap.currency_in` is pool currency SwapIntoPool(Swap), + /// NOTE: Assumes `swap.currency_in` is return currency SwapIntoReturn(Swap), } From 76d025153acbf12eac0eba16556866caf274aae8 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 19 Jul 2023 09:36:47 +0200 Subject: [PATCH 05/96] feat: handle invest increase transitions --- pallets/foreign-investments/src/impls.rs | 416 +++++++++++++++++++---- pallets/foreign-investments/src/lib.rs | 2 - pallets/foreign-investments/src/types.rs | 20 +- 3 files changed, 367 insertions(+), 71 deletions(-) diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index 1de907dc13..14aac8bef2 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -15,7 +15,7 @@ use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwa use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; use frame_support::{traits::Get, transactional}; use sp_runtime::{ - traits::{EnsureAdd, Zero}, + traits::{EnsureAdd, EnsureSub, Zero}, DispatchError, DispatchResult, }; @@ -81,6 +81,7 @@ impl ForeignInvestment for Pallet { let pre_amount = T::Investment::investment(who, investment_id.clone())?; let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + // TODO: Add check for same currencies, i.e. no swap required if amount > pre_amount { let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, @@ -111,11 +112,11 @@ impl Pallet { state: InvestState, ) -> DispatchResult { match state.clone() { - InvestState::NoState => { + InvestState::NoState=> { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, Zero::zero())?; - // Exit early to prevent setting InvestmentState to `NoState` + // Exit early to prevent setting InvestmentState InvestmentState::::remove(who, investment_id); return Ok(()); }, @@ -123,8 +124,8 @@ impl Pallet { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, invest_amount)?; }, - InvestState::ActiveSwapIntoPoolCurrency(swap) | - InvestState::ActiveSwapIntoReturnCurrency(swap) | + InvestState::ActiveSwapIntoPoolCurrency { swap } | + InvestState::ActiveSwapIntoReturnCurrency { swap } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { Self::place_swap_order(who, investment_id, swap)?; @@ -138,26 +139,47 @@ impl Pallet { T::Investment::update_investment(who, investment_id, invest_amount)?; }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::place_swap_order(who, investment_id, swap)?; + Self::place_swap_order(who, investment_id, swap.clone())?; T::Investment::update_investment(who, investment_id, Zero::zero())?; - // Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::place_swap_order(who, investment_id, swap)?; + Self::place_swap_order(who, investment_id, swap.clone())?; T::Investment::update_investment(who, investment_id, invest_amount)?; Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); }, - InvestState::SwapIntoReturnDone(_swap) => { + InvestState::SwapIntoReturnDone { swap } => { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, Zero::zero())?; + + Self::send_executed_decrease_hook(who, investment_id, swap.amount)?; + + // Exit early to prevent setting InvestmentState + InvestmentState::::remove(who, investment_id); + return Ok(()); }, InvestState::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount } => { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, invest_amount)?; + + Self::send_executed_decrease_hook(who, investment_id, swap.amount)?; + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::InvestmentOngoing { invest_amount }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); }, }; @@ -245,8 +267,8 @@ impl Pallet { impl InvestState where - Balance: Clone + Copy + EnsureAdd, - Currency: Clone + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, { /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. @@ -272,73 +294,271 @@ where // Actual impl of transition impl InvestState where - Balance: Clone + Copy + EnsureAdd, - Currency: Clone + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, { - // fn swap_required(&self, - // return_currency: Currency, - // pool_currency: Currency, - // amount: Balance - // ) -> Result { - // if return_currency == pool_currency { - - // } - // } - + // TODO: Add to spec /// Handle `increase` transitions depicted by `msg::increase` edges in the - /// state diagram. + /// state diagram. Behaves similar to a ledger when considering + /// `SwapIntoReturnDone` and `InvestmentOngoing` as the + /// + /// When we increase an investment, we normally have to swap it into pool + /// currency (`ActiveSwapIntoPoolCurrency`) before it can be invested + /// (`ActiveInvestmentOngoing`). However, if the current state includes + /// swapping back into pool currency (`ActiveSwapIntoReturnCurrency`) as the + /// result of a previous decrement, then we can minimize the amount which + /// needs to be swapped such that we always have **at most a single active + /// swap** which is the maximum of `pool_swap.amount` and + /// `return_swap.amount`. When we do this, we always need to bump the + /// investment amount as well as the `SwapIntoReturnDone` amount as a result + /// of immediately fulfilling the pool swap order up to the possible amount. + /// + /// Example: + /// * Say before my pre state has `return_done = 1000` and + /// `return_swap.amount = 500`. Now we look at three scenarios in which we + /// increase below, exactly at and above the `return_swap.amount`: + /// * a) If we increase by 500, we can reduce the `return_swap.amount` + /// fully, which we denote by adding the 500 to the `return_done` amount. + /// Moreover, we can immediately invest the 500. The resulting state is + /// `(done_amount = 1500, investing = 500)`. + /// * b) If we increase by 400, we can reduce the `return_swap.amount` only + /// by 400 and increase both the `investing` as well as `return_done` + /// amount by that. The resulting state is + /// `(done_amount = 1400, return_swap.amount = 100, investing = 400)`. + /// * c) If we increase by 600, we can reduce the `return_swap.amount` fully + /// and need to add a swap into pool currency for 100. Moreover both the + /// `investing` as well as `return_done` amount can only be increased by + /// 500. The resulting state is + /// `(done_amount = 1500, pool_swap.amount = 100, investing = 500)`. + /// + /// NOTE: We can ignore handling all states which include + /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// consume the done amount and transition in the post transition phase. fn handle_increase(&self, swap: Swap) -> Result { match &self { - Self::NoState => { - if swap.currency_in == swap.currency_out { - Ok(Self::InvestmentOngoing { - invest_amount: swap.amount, - }) - } else { - Ok(Self::ActiveSwapIntoPoolCurrency(swap)) - } - } + Self::NoState => Ok(Self::ActiveSwapIntoPoolCurrency { swap }), + // Add pool swap Self::InvestmentOngoing { invest_amount } => { - if swap.currency_in == swap.currency_out { - Ok(Self::InvestmentOngoing { - invest_amount: invest_amount.ensure_add(swap.amount)?, - }) - } else { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap, - invest_amount: *invest_amount, + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap, + invest_amount: *invest_amount, + }) + } + // Bump pool swap + Self::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Ok(Self::ActiveSwapIntoPoolCurrency { + swap: Swap { + amount: swap.amount.ensure_add(pool_swap.amount)?, + ..swap + }, + }) + } + // Reduce return swap amount by the increasing amount and increase investing amount as + // well adding return_done amount by the minimum of active swap amounts + Self::ActiveSwapIntoReturnCurrency { swap: return_swap } => { + let invest_amount = swap.amount.min(return_swap.amount); + let done_amount = swap + .amount + .min(return_swap.amount) + .ensure_add(*done_amount)?; + + // pool swap amount is immediately invested and done amount increased equally + if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }) + } + // swap amount is immediately invested and done amount increased equally + else if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + swap: *return_swap, + invest_amount, }) } + // return swap amount is immediately invested and done amount increased equally + else { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, + }, + ) + } } - Self::ActiveSwapIntoPoolCurrency(_) => todo!(), - Self::ActiveSwapIntoReturnCurrency(_) => todo!(), + // Bump pool swap Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap, + swap: pool_swap, invest_amount, - } => todo!(), + } => Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: swap.amount.ensure_add(pool_swap.amount)?, + ..swap + }, + invest_amount: *invest_amount, + }), + // Reduce return swap amount by the increasing amount and increase investing amount as + // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap, + swap: return_swap, invest_amount, - } => todo!(), - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => todo!(), - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - todo!() + } => { + let invest_amount = + invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; + let done_amount = swap + .amount + .min(return_swap.amount) + .ensure_add(*done_amount)?; + + // pool swap amount is immediately invested and done amount increased equally + if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }) + } + // swap amount is immediately invested and done amount increased equally + else if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + swap: *return_swap, + invest_amount, + }) + } + // return swap amount is immediately invested and done amount increased equally + else { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, + }, + ) + } } - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap, + // Reduce amount of return by the increasing amount and increase investing as well as + // return_done amount by the minimum of active swap amounts + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: return_swap, done_amount, - invest_amount, - } => todo!(), + } => { + let invest_amount = swap.amount.min(return_swap.amount); + let done_amount = invest_amount.ensure_add(*done_amount)?; + + // pool swap amount is immediately invested and done amount increased equally + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + amount: done_amount, + ..*return_swap + }, + invest_amount, + }) + } + // swap amount is immediately invested and done amount increased equally + else if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, done_amount, invest_amount }) + } + // return swap amount is immediately invested and done amount increased equally + else { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, + }, + ) + } + } + // Reduce amount of return swap by increasing amount and increase investing as well as + // return_done amount by minimum of swap amounts Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap, + swap: return_swap, done_amount, invest_amount, - } => todo!(), - Self::SwapIntoReturnDone(_) => todo!(), - Self::SwapIntoReturnDoneAndInvestmentOngoing { - swap, - invest_amount, - } => todo!(), + } => { + let invest_amount = + invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; + let done_amount = swap + .amount + .min(return_swap.amount) + .ensure_add(*done_amount)?; + + // pool swap amount is immediately invested and done amount increased equally + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + amount: done_amount, + ..*return_swap + }, + invest_amount, + }) + } + // swap amount is immediately invested and done amount increased equally + else if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, done_amount, invest_amount }) + } + // return swap amount is immediately invested and done amount increased equally + else { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, + }, + ) + } + } + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => { + Err(DispatchError::Corruption) + } + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + .. + } => Err(DispatchError::Corruption), + // Should be cleared entirely in post transition trigger and thus never exist as pre + // transition state + Self::SwapIntoReturnDone { .. } => Err(DispatchError::Corruption), + // Should be updated to `InvestmentOngoing` in post transition trigger and thus never + // exist as pre transition state + Self::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), } } @@ -372,6 +592,78 @@ where ) -> Result { todo!("Do state transition here") } + + // TODO(@review): Do we need to handle this case at all or assume to always have + // required swaps through foreign investments? + // fn handle_increase_non_foreign(&self, swap: Swap) -> + // Result { match &self { + // Self::NoState => { + // Ok(Self::InvestmentOngoing { + // invest_amount: swap.amount, + // }) + // } + // Self::InvestmentOngoing { invest_amount } => { + // Ok(Self::InvestmentOngoing { + // invest_amount: invest_amount.ensure_add(swap.amount)?, + // }) + // } + // Self::ActiveSwapIntoPoolCurrency { ..} => todo!(), + // Self::ActiveSwapIntoReturnCurrency { ..} => todo!(), + // Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + // swap, + // invest_amount, + // } => todo!(), + // Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + // swap, + // invest_amount, + // } => todo!(), + // Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } + // => todo!(), Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, + // done_amount } => { todo!() + // } + // Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + // swap, + // done_amount, + // invest_amount, + // } => todo!(), + // Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + // swap, + // done_amount, + // invest_amount, + // } => todo!(), + // Self::SwapIntoReturnDone(done_swap) => { + // if swap.currency_in == swap.currency_out { + // if swap.amount < done_swap.amount { + // Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { + // swap: Swap { + // currency_in: swap.currency_out, + // currency_out: swap.currency_in, + // amount: done_swap.amount.ensure_sub(swap.amount)?, + // }, + // invest_amount: swap.amount, + // }) + // } else { + // Ok(Self::InvestmentOngoing { + // invest_amount: swap.amount, + // }) + // } + // } else { + // if swap.amount < done_swap.amount { + // let done_amount = done_swap.amount.ensure_sub(swap.amount)?; + // Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + // swap, + // done_amount, + // }) + // } else { + // Ok(Self::ActiveSwapIntoPoolCurrency { swap }) + // } + // } + // } + // Self::SwapIntoReturnDoneAndInvestmentOngoing { + // swap, + // invest_amount, + // } => todo!(), + // } } // TODO: How to merge token swaps and investment trait? Create new trait diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 2f3eb61ea0..bca365c71d 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -166,14 +166,12 @@ pub mod pallet { type ExecutedDecreaseHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - // TODO: Move to type Status = ExecutedDecrease, Error = DispatchError, >; type ExecutedCollectHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - // TODO: Convert to type Status = ExecutedCollect, Error = DispatchError, >; diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 832566d122..cab9d0b87a 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -13,7 +13,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::traits::EnsureAdd; +use sp_runtime::traits::{EnsureAdd, EnsureSub}; // TODO: Might want to use this trimmed down version of InvestmentInfo for the // ForeignInvestmentInfo storage in case we don't need to store the payment @@ -29,7 +29,7 @@ use sp_runtime::traits::EnsureAdd; #[derive( Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] -pub struct Swap { +pub struct Swap { pub currency_in: Currency, pub currency_out: Currency, pub amount: Balance, @@ -41,16 +41,19 @@ pub struct Swap #[derive( Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] -pub enum InvestState { +pub enum InvestState< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +> { #[default] NoState, /// The investment is waiting to be processed. InvestmentOngoing { invest_amount: Balance }, /// The investment is currently swapped into the required pool currency. - ActiveSwapIntoPoolCurrency(Swap), + ActiveSwapIntoPoolCurrency { swap: Swap }, /// The unprocessed investment was fully decreased and is currently swapped /// back into the corresponding return currency. - ActiveSwapIntoReturnCurrency(Swap), + ActiveSwapIntoReturnCurrency { swap: Swap }, /// The investment is not fully swapped into pool currency and thus split /// into two: /// * One part is still being swapped. @@ -117,7 +120,7 @@ pub enum InvestState), + SwapIntoReturnDone { swap: Swap }, // TODO: Maybe remove /// The investment is split into two: /// * One part is waiting to be processed as an investment @@ -134,7 +137,10 @@ pub enum InvestState { +pub enum InvestTransition< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +> { /// NOTE: Assumes `swap.currency_in` is pool currency IncreaseInvestOrder(Swap), /// NOTE: Assumes `swap.currency_in` is return currency From 0855e0b618bc7042d110e13f202eae3feb5d4256 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 19 Jul 2023 12:14:51 +0200 Subject: [PATCH 06/96] feat: handle invest decrease transitions --- pallets/foreign-investments/src/impls.rs | 229 ++++++++++++++++++++--- pallets/foreign-investments/src/types.rs | 13 +- 2 files changed, 211 insertions(+), 31 deletions(-) diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index 14aac8bef2..9b759d3d7d 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -16,7 +16,7 @@ use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; use frame_support::{traits::Get, transactional}; use sp_runtime::{ traits::{EnsureAdd, EnsureSub, Zero}, - DispatchError, DispatchResult, + ArithmeticError, DispatchError, DispatchResult, }; use crate::{ @@ -132,9 +132,9 @@ impl Pallet { T::Investment::update_investment(who, investment_id, Zero::zero())?; }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into return is fulfilled - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount, .. } => { + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { Self::place_swap_order(who, investment_id, swap)?; T::Investment::update_investment(who, investment_id, invest_amount)?; }, @@ -154,7 +154,7 @@ impl Pallet { T::Investment::update_investment(who, investment_id, invest_amount)?; Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - + // Exit early to prevent setting InvestmentState let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; InvestmentState::::insert(who, investment_id, new_state); @@ -163,7 +163,7 @@ impl Pallet { InvestState::SwapIntoReturnDone { swap } => { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, Zero::zero())?; - + Self::send_executed_decrease_hook(who, investment_id, swap.amount)?; // Exit early to prevent setting InvestmentState @@ -357,22 +357,19 @@ where // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrency { swap: return_swap } => { let invest_amount = swap.amount.min(return_swap.amount); - let done_amount = swap - .amount - .min(return_swap.amount) - .ensure_add(*done_amount)?; + let done_amount = swap.amount.min(return_swap.amount); // pool swap amount is immediately invested and done amount increased equally if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, - done_amount, - invest_amount, - }) + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }) } // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { @@ -415,22 +412,19 @@ where } => { let invest_amount = invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; - let done_amount = swap - .amount - .min(return_swap.amount) - .ensure_add(*done_amount)?; + let done_amount = swap.amount.min(return_swap.amount); // pool swap amount is immediately invested and done amount increased equally if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, - done_amount, - invest_amount, - }) + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }) } // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { @@ -564,8 +558,183 @@ where /// Handle `decrease` transitions depicted by `msg::decrease` edges in the /// state diagram. + /// + /// NOTE: Throws the decreasing amount can never exceed the the amount which + /// is swapping into pool currency and/or investing. fn handle_decrease(&self, swap: Swap) -> Result { - todo!("Do state transition here") + match &self { + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency + InvestState::NoState => Err(DispatchError::Corruption), + // Increment return swap amount up to ongoing investment + InvestState::InvestmentOngoing { invest_amount } => { + if swap.amount < *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount: *invest_amount - swap.amount }) + } else if swap.amount == *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrency { swap }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Increment return done amount up to amount of the active pool swap + InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + if swap.amount == pool_swap.amount { + Ok(Self::SwapIntoReturnDone { swap }) + } else if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: Swap { + // safe because swap.amount < pool_swap.amount + amount: pool_swap.amount - swap.amount, + ..*pool_swap + }, done_amount: swap.amount}) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency + InvestState::ActiveSwapIntoReturnCurrency { swap } => Err(DispatchError::Corruption), + // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + let done_amount = swap.amount.min(pool_swap.amount); + let invest_amount = invest_amount.ensure_sub(done_amount)?; + let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; + + if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe because done_amount is min + amount: pool_swap.amount - done_amount, + ..*pool_swap + }, done_amount, invest_amount }) + } else if swap.amount == pool_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount }) + } else if swap.amount < max_decrease_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe because done_amount is min + amount: swap.amount - done_amount, + ..swap + }, done_amount, invest_amount }) + } else if swap.amount == max_decrease_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { + // safe because done_amount is min + amount: swap.amount - done_amount, + ..swap + }, done_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Increment return swap up to ongoing investment + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + let amount = return_swap.amount.ensure_add(swap.amount)?; + + if swap.amount < *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: Swap { + amount, + ..swap + }, + // safe because invest_amount > swap_amount + invest_amount: *invest_amount - swap.amount }) + } else if swap.amount == *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrency { swap: Swap { + amount, + ..swap + } }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Increment return_done amount up to pool swap amount + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: pool_swap, done_amount } => { + let done_amount = done_amount.ensure_add(swap.amount.min(pool_swap.amount))?; + + if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: Swap { + amount: pool_swap.amount - done_amount, + ..*pool_swap + }, done_amount }) + } else if swap.amount == pool_swap.amount { + Ok(Self::SwapIntoReturnDone { swap: Swap { + amount: done_amount, + ..swap + } }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Err(DispatchError::Corruption), + // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: pool_swap, done_amount, invest_amount } => { + let return_amount = swap.amount.min(pool_swap.amount); + let done_amount = done_amount.ensure_add(return_amount)?; + let invest_amount = invest_amount.ensure_sub(return_amount)?; + let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; + + if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe because return_amount is min + amount: pool_swap.amount - return_amount, + ..*pool_swap + }, done_amount, invest_amount }) + } else if swap.amount == pool_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount }) + } else if swap.amount < max_decrease_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe because return_amount is min + amount: swap.amount - return_amount, + ..swap + }, done_amount, invest_amount }) + } else if swap.amount == max_decrease_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { + // safe because return_amount is min + amount: swap.amount - return_amount, + ..swap + }, done_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + let amount = return_swap.amount.ensure_add(swap.amount)?; + + if swap.amount < *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount, ..swap}, done_amount: *done_amount, + // safe because swap.amount < invest_amount + invest_amount: *invest_amount - swap.amount }) + } else if swap.amount == *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount, ..swap}, done_amount: *done_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency + InvestState::SwapIntoReturnDone { swap } => Err(DispatchError::Corruption), + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount: done_amount, .. }, invest_amount } => { + if swap.amount < *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount: *done_amount, + // safe because swap.amount < invest_amount + invest_amount: *invest_amount - swap.amount }) + } else if swap.amount == *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount: *done_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + }, + } } /// Handle partial/full token swap order transitions into pool currency diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index cab9d0b87a..99d4c448b9 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -27,7 +27,18 @@ use sp_runtime::traits::{EnsureAdd, EnsureSub}; // } #[derive( - Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, + Clone, + Default, + Copy, + PartialOrd, + Ord, + PartialEq, + Eq, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, )] pub struct Swap { pub currency_in: Currency, From 339f8a1cb06e7a42a9523d20bf8958b0611ed66e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 19 Jul 2023 16:35:42 +0200 Subject: [PATCH 07/96] feat: handle invest swap order transitions --- Cargo.lock | 1 + pallets/foreign-investments/Cargo.toml | 2 + pallets/foreign-investments/src/impls.rs | 291 ++++++++++++++--------- pallets/foreign-investments/src/types.rs | 29 +-- 4 files changed, 197 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b467a1d2f..bed14254b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7326,6 +7326,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec 3.4.0", "scale-info", "sp-core", diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml index 799a8d9be3..d07585ef4d 100644 --- a/pallets/foreign-investments/Cargo.toml +++ b/pallets/foreign-investments/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } +log = { version = "0.4.17", default-features = false } scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } cfg-primitives = { path = "../../libs/primitives", default-features = false } @@ -41,6 +42,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-runtime/std", ] diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index 9b759d3d7d..f04b643f96 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -40,23 +40,20 @@ impl StatusNotificationHook for Pallet { status: SwapOf, ) -> Result<(), DispatchError> { let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; - let pre_state = InvestmentState::::get(info.owner, info.id).unwrap_or_default(); - - match status.currency_in { - pool_currency if T::Investment::accepted_payment_currency(info.id, pool_currency) => { - pre_state - .transition(InvestTransition::SwapIntoPool(status)) - .map(|_| ()) - } - return_currency - if T::Investment::accepted_payout_currency(info.id, return_currency) => - { - pre_state - .transition(InvestTransition::SwapIntoReturn(status)) - .map(|_| ()) - } - _ => Err(Error::::InvalidInvestmentCurrency.into()), - } + let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); + + let post_state = pre_state.transition(InvestTransition::FulfillSwapOrder(status)) + .map_err(|e| { + log::debug!("Encountered unexpected pre state {:?} when transitioning into {:?} after (partially) fulfilling a swap", pre_state, status); + e + })?; + Pallet::::apply_state_transition(&info.owner, info.id, post_state.clone()).map(|e| { + log::debug!( + "Encountered unexpected error when applying state transition to state {:?}", + post_state + ); + e + }) } } @@ -281,11 +278,8 @@ where match transition { InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(&self, swap), InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(&self, swap), - InvestTransition::SwapIntoPool(swap) => { - Self::handle_fulfilled_swap_into_pool(&self, swap) - } - InvestTransition::SwapIntoReturn(swap) => { - Self::handle_fulfilled_swap_into_return(&self, swap) + InvestTransition::FulfillSwapOrder(swap) => { + Self::handle_fulfilled_swap_order(&self, swap) } } } @@ -334,6 +328,9 @@ where /// NOTE: We can ignore handling all states which include /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. + /// To be safe and not make any unhandled assumptions, we throw + /// `DispatchError::Corruption` for these states though we need to make sure + /// this can never occur! fn handle_increase(&self, swap: Swap) -> Result { match &self { Self::NoState => Ok(Self::ActiveSwapIntoPoolCurrency { swap }), @@ -559,8 +556,23 @@ where /// Handle `decrease` transitions depicted by `msg::decrease` edges in the /// state diagram. /// - /// NOTE: Throws the decreasing amount can never exceed the the amount which - /// is swapping into pool currency and/or investing. + /// Throws if the decreasing amount exceeds the amount which is + /// currently swapping into pool currency and/or investing as we cannot + /// decrease more than was invested. We must ensure, this can never happen + /// at this stage! + /// + /// NOTE: We can ignore handling all states which include + /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// consume the done amount and transition in the post transition phase. + /// To be safe and not make any unhandled assumptions, we throw + /// `DispatchError::Corruption` for these states though we need to make sure + /// this can never occur! + /// + /// Moreover, we can ignore handling all states which do not include + /// `ActiveSwapIntoPoolCurrency` or `InvestmentOngoing` as we cannot reduce + /// further then. To be safe and not make any unhandled assumptions, we + /// throw `DispatchError::Corruption` for these states though we need to + /// make sure this can never occur! fn handle_decrease(&self, swap: Swap) -> Result { match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency @@ -649,117 +661,184 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Increment return_done amount up to pool swap amount - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: pool_swap, done_amount } => { - let done_amount = done_amount.ensure_add(swap.amount.min(pool_swap.amount))?; + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Err(DispatchError::Corruption), + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + let amount = return_swap.amount.ensure_add(swap.amount)?; - if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: Swap { - amount: pool_swap.amount - done_amount, - ..*pool_swap - }, done_amount }) - } else if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDone { swap: Swap { - amount: done_amount, - ..swap - } }) + if swap.amount < *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount, ..swap}, done_amount: *done_amount, + // safe because swap.amount < invest_amount + invest_amount: *invest_amount - swap.amount }) + } else if swap.amount == *invest_amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount, ..swap}, done_amount: *done_amount }) } // should never occur but let's be safe here else { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Err(DispatchError::Corruption), - // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: pool_swap, done_amount, invest_amount } => { - let return_amount = swap.amount.min(pool_swap.amount); - let done_amount = done_amount.ensure_add(return_amount)?; - let invest_amount = invest_amount.ensure_sub(return_amount)?; - let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Corruption), + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + // Should be cleared entirely in post transition trigger and thus never exist as pre + // transition state + InvestState::SwapIntoReturnDone {.. } => Err(DispatchError::Corruption), + // Should be updated to `InvestmentOngoing` in post transition trigger and thus never + // exist as pre transition state + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + } + } - if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe because return_amount is min - amount: pool_swap.amount - return_amount, - ..*pool_swap - }, done_amount, invest_amount }) - } else if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount }) - } else if swap.amount < max_decrease_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe because return_amount is min - amount: swap.amount - return_amount, + /// Handle partial/full token swap order transitions depicted by + /// `order_partial` and `order_full` edges in the state diagram. + /// + /// Please note, that we ensure that there can always be at most one swap, + /// either into pool currency (`ActiveSwapIntoPoolCurrency`) or into return + /// currency (`ActiveSwapIntoReturnCurrency`). Thus, if the previous state + /// (`&self`) is into pool, we know the incoming transition is made from + /// return into pool currency and vice versa if the previous state is + /// swapping into return currency. + /// + /// This transition should always increase the active ongoing + /// investment. + /// + /// NOTE: We can ignore handling all states which include + /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// consume the done amount and transition in the post transition phase. + /// To be safe and not make any unhandled assumptions, we throw + /// `DispatchError::Corruption` for these states though we need to make sure + /// this can never occur! + /// + /// Moreover, we can ignore handling all states which do not include + /// `ActiveSwapInto{Pool, Return}Currency`. To be safe and not make any + /// unhandled assumptions, we throw `DispatchError::Corruption` for these + /// states though we need to make sure this can never occur! + fn handle_fulfilled_swap_order( + &self, + swap: Swap, + ) -> Result { + match &self { + InvestState::NoState => Err(DispatchError::Corruption), + InvestState::InvestmentOngoing { invest_amount } => Err(DispatchError::Corruption), + // Increment ongoing investment by swapped amount + InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + if swap.amount == pool_swap.amount { + Ok(Self::InvestmentOngoing { invest_amount: swap.amount }) + } else if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, ..swap - }, done_amount, invest_amount }) - } else if swap.amount == max_decrease_amount { + }, invest_amount: swap.amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } + }, + // Increment done_return by swapped amount + InvestState::ActiveSwapIntoReturnCurrency { swap: return_swap } => { + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDone { swap }) + } else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - // safe because return_amount is min - amount: swap.amount - return_amount, + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, ..swap - }, done_amount }) + }, done_amount: swap.amount }) } // should never occur but let's be safe here else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) } }, - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { - let amount = return_swap.amount.ensure_add(swap.amount)?; + // Increment ongoing investment by swapped amount + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + let invest_amount = invest_amount.ensure_add(swap.amount)?; - if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount, ..swap}, done_amount: *done_amount, - // safe because swap.amount < invest_amount - invest_amount: *invest_amount - swap.amount }) - } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount, ..swap}, done_amount: *done_amount }) + if swap.amount == pool_swap.amount { + Ok(Self::InvestmentOngoing { invest_amount }) + } else if swap.amount < pool_swap.amount { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, + ..swap + }, invest_amount }) } // should never occur but let's be safe here else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) } }, - // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::SwapIntoReturnDone { swap } => Err(DispatchError::Corruption), - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount: done_amount, .. }, invest_amount } => { - if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount: *done_amount, - // safe because swap.amount < invest_amount - invest_amount: *invest_amount - swap.amount }) - } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount: *done_amount }) + // Increment done_return by swapped amount, leave invest amount untouched + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount: *invest_amount }) + } else if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, done_amount: swap.amount, invest_amount: *invest_amount }) } // should never occur but let's be safe here else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) } }, - } - } + // Increment done_return by swapped amount + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: return_swap, done_amount } => { + let done_amount = done_amount.ensure_add(swap.amount)?; - /// Handle partial/full token swap order transitions into pool currency - /// depicted by `order_partial` edges in the state diagram where the swap - /// currency matches the pool one. - /// - /// NOTE: These should always increase the active ongoing investment. - fn handle_fulfilled_swap_into_pool( - &self, - swap: Swap, - ) -> Result { - todo!("Do state transition here") - } + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDone { swap: Swap { amount: done_amount, ..swap } }) + } else if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, done_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } + }, + // Increment done_return by swapped amount, leave invest amount untouched + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + let done_amount = done_amount.ensure_add(swap.amount)?; - /// Handle partial/full token swap order transitions into return currency - /// depicted by `order_partial` edges in the state diagram with the swap - /// currency matches the return one. - /// - /// NOTE: Assumes the corresponding investment has been decreased - /// beforehand. - fn handle_fulfilled_swap_into_return( - &self, - swap: Swap, - ) -> Result { - todo!("Do state transition here") + if swap.amount == return_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount: done_amount, ..swap }, invest_amount: *invest_amount }) + } else if swap.amount < return_swap.amount { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing{ swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, done_amount, invest_amount: *invest_amount }) + } + // should never occur but let's be safe here + else { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } + }, + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Corruption), + // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post + // transition trigger and thus never exist as pre transition state + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + // Should be cleared entirely in post transition trigger and thus never exist as pre + // transition state + InvestState::SwapIntoReturnDone {.. } => Err(DispatchError::Corruption), + // Should be updated to `InvestmentOngoing` in post transition trigger and thus never + // exist as pre transition state + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + } } // TODO(@review): Do we need to handle this case at all or assume to always have diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 99d4c448b9..06709c0ef3 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -15,17 +15,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::traits::{EnsureAdd, EnsureSub}; -// TODO: Might want to use this trimmed down version of InvestmentInfo for the -// ForeignInvestmentInfo storage in case we don't need to store the payment -// currency -// #[derive( -// Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, -// TypeInfo, MaxEncodedLen, )] -// pub struct ForeignInvestment { -// pub investor: Balance, -// pub investment_id: InvestmentId, -// } - #[derive( Clone, Default, @@ -126,13 +115,11 @@ pub enum InvestState< done_amount: Balance, invest_amount: Balance, }, - // TODO: Maybe remove /// The unprocessed investment was swapped back into return currency. /// /// NOTE: This state can be killed by applying the corresponding trigger to /// handle the return amount. SwapIntoReturnDone { swap: Swap }, - // TODO: Maybe remove /// The investment is split into two: /// * One part is waiting to be processed as an investment /// * The swapped back into the return currency as a result of @@ -147,17 +134,19 @@ pub enum InvestState< } #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] -// TODO: Complete pub enum InvestTransition< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, Currency: Clone + Copy + PartialEq, > { - /// NOTE: Assumes `swap.currency_in` is pool currency + /// Assumes `swap.currency_in` is pool currency as we increase here. IncreaseInvestOrder(Swap), - /// NOTE: Assumes `swap.currency_in` is return currency + /// Assumes `swap.currency_in` is return currency as we decrease here. DecreaseInvestOrder(Swap), - /// NOTE: Assumes `swap.currency_in` is pool currency - SwapIntoPool(Swap), - /// NOTE: Assumes `swap.currency_in` is return currency - SwapIntoReturn(Swap), + /// Implicitly derives `swap.currency_in` and `swap.currency_out` from + /// previous state: + /// * If the previous state includes `ActiveSwapIntoPoolCurrency`, + /// `currency_in` is the pool currency. + /// * If the previous state includes `ActiveSwapIntoReturnCurrency`, + /// `currency_in` is the return currency. + FulfillSwapOrder(Swap), } From 1b282f41a400ceb4cc0353631a15e23bd565d2cf Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 20 Jul 2023 11:32:28 +0200 Subject: [PATCH 08/96] feat: handle same currencies, cleanup --- pallets/foreign-investments/src/impls.rs | 314 ++++++++++++----------- 1 file changed, 165 insertions(+), 149 deletions(-) diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index f04b643f96..cc134c398d 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -78,30 +78,34 @@ impl ForeignInvestment for Pallet { let pre_amount = T::Investment::investment(who, investment_id.clone())?; let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); - // TODO: Add check for same currencies, i.e. no swap required - if amount > pre_amount { - let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { + let post_state = if amount > pre_amount { + pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, currency_out: return_currency, amount, - }))?; - Ok(()) + })) } else if amount < pre_amount { - let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { + pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { currency_in: return_currency, currency_out: pool_currency, amount, - }))?; - Ok(()) + })) } else { - Ok(()) - } + Ok(pre_state) + }?; + + Pallet::::apply_state_transition(who, investment_id, post_state)?; + + Ok(()) } + + // TODO: Add similar functions for redemptions and collections } impl Pallet { - /// Updates chain storage after applying state transition of `InvestState` - /// and execute `ExecutedDecreaseHook`. + /// Must be called after transitioning any `InvestState` via `transition` to + /// update the chain storage and execute various trait config hooks, e.g. + /// `ExecutedDecreaseHook`. #[transactional] fn apply_state_transition( who: &T::AccountId, @@ -270,7 +274,8 @@ where /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. /// - /// NOTE: Does not mutate storage which is done by `apply_state_transition`. + /// NOTE: MUST call `apply_state_transition` on the post state to actually + /// mutate storage. pub fn transition( &self, transition: InvestTransition, @@ -329,9 +334,14 @@ where /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. /// To be safe and not make any unhandled assumptions, we throw - /// `DispatchError::Corruption` for these states though we need to make sure + /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! fn handle_increase(&self, swap: Swap) -> Result { + // TODO(@review): Can we check this at an earlier stage? + if swap.currency_in == swap.currency_out { + return Self::handle_increase_non_foreign(&self, swap); + } + match &self { Self::NoState => Ok(Self::ActiveSwapIntoPoolCurrency { swap }), // Add pool swap @@ -343,6 +353,7 @@ where } // Bump pool swap Self::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Self::ensure_currencies_match(true, &swap, pool_swap)?; Ok(Self::ActiveSwapIntoPoolCurrency { swap: Swap { amount: swap.amount.ensure_add(pool_swap.amount)?, @@ -353,6 +364,7 @@ where // Reduce return swap amount by the increasing amount and increase investing amount as // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrency { swap: return_swap } => { + Self::ensure_currencies_match(false, &swap, return_swap)?; let invest_amount = swap.amount.min(return_swap.amount); let done_amount = swap.amount.min(return_swap.amount); @@ -394,19 +406,25 @@ where Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount, - } => Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: swap.amount.ensure_add(pool_swap.amount)?, - ..swap - }, - invest_amount: *invest_amount, - }), + } => { + Self::ensure_currencies_match(true, &swap, pool_swap)?; + + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: swap.amount.ensure_add(pool_swap.amount)?, + ..swap + }, + invest_amount: *invest_amount, + } + ) + }, // Reduce return swap amount by the increasing amount and increase investing amount as // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount, } => { + Self::ensure_currencies_match(false, &swap, return_swap)?; let invest_amount = invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; let done_amount = swap.amount.min(return_swap.amount); @@ -451,6 +469,7 @@ where swap: return_swap, done_amount, } => { + Self::ensure_currencies_match(false, &swap, return_swap)?; let invest_amount = swap.amount.min(return_swap.amount); let done_amount = invest_amount.ensure_add(*done_amount)?; @@ -467,10 +486,10 @@ where // swap amount is immediately invested and done amount increased equally else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, done_amount, invest_amount }) + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, done_amount, invest_amount }) } // return swap amount is immediately invested and done amount increased equally else { @@ -494,6 +513,7 @@ where done_amount, invest_amount, } => { + Self::ensure_currencies_match(false, &swap, return_swap)?; let invest_amount = invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; let done_amount = swap @@ -514,10 +534,10 @@ where // swap amount is immediately invested and done amount increased equally else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, done_amount, invest_amount }) + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, done_amount, invest_amount }) } // return swap amount is immediately invested and done amount increased equally else { @@ -534,22 +554,7 @@ where ) } } - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => { - Err(DispatchError::Corruption) - } - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - .. - } => Err(DispatchError::Corruption), - // Should be cleared entirely in post transition trigger and thus never exist as pre - // transition state - Self::SwapIntoReturnDone { .. } => Err(DispatchError::Corruption), - // Should be updated to `InvestmentOngoing` in post transition trigger and thus never - // exist as pre transition state - Self::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) } } @@ -565,18 +570,23 @@ where /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. /// To be safe and not make any unhandled assumptions, we throw - /// `DispatchError::Corruption` for these states though we need to make sure + /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! /// /// Moreover, we can ignore handling all states which do not include /// `ActiveSwapIntoPoolCurrency` or `InvestmentOngoing` as we cannot reduce /// further then. To be safe and not make any unhandled assumptions, we - /// throw `DispatchError::Corruption` for these states though we need to + /// throw `DispatchError::Other` for these states though we need to /// make sure this can never occur! fn handle_decrease(&self, swap: Swap) -> Result { + // TODO(@review): Can we check this at an earlier stage? + if swap.currency_in == swap.currency_out { + return Self::handle_decrease_non_foreign(&self, swap); + } + match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::NoState => Err(DispatchError::Corruption), + InvestState::NoState | InvestState::ActiveSwapIntoReturnCurrency { .. } | InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Other("Invalid pre state when transitioning a decrease")), // Increment return swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { if swap.amount < *invest_amount { @@ -591,6 +601,8 @@ where }, // Increment return done amount up to amount of the active pool swap InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Self::ensure_currencies_match(false, &swap, pool_swap)?; + if swap.amount == pool_swap.amount { Ok(Self::SwapIntoReturnDone { swap }) } else if swap.amount < pool_swap.amount { @@ -605,10 +617,9 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::ActiveSwapIntoReturnCurrency { swap } => Err(DispatchError::Corruption), // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + Self::ensure_currencies_match(false, &swap, pool_swap)?; let done_amount = swap.amount.min(pool_swap.amount); let invest_amount = invest_amount.ensure_sub(done_amount)?; let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; @@ -641,6 +652,7 @@ where }, // Increment return swap up to ongoing investment InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { @@ -661,9 +673,8 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Err(DispatchError::Corruption), InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { @@ -678,18 +689,8 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Corruption), - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), - // Should be cleared entirely in post transition trigger and thus never exist as pre - // transition state - InvestState::SwapIntoReturnDone {.. } => Err(DispatchError::Corruption), - // Should be updated to `InvestmentOngoing` in post transition trigger and thus never - // exist as pre transition state - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) + } } @@ -710,22 +711,23 @@ where /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. /// To be safe and not make any unhandled assumptions, we throw - /// `DispatchError::Corruption` for these states though we need to make sure + /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! /// /// Moreover, we can ignore handling all states which do not include /// `ActiveSwapInto{Pool, Return}Currency`. To be safe and not make any - /// unhandled assumptions, we throw `DispatchError::Corruption` for these + /// unhandled assumptions, we throw `DispatchError::Other` for these /// states though we need to make sure this can never occur! fn handle_fulfilled_swap_order( &self, swap: Swap, ) -> Result { match &self { - InvestState::NoState => Err(DispatchError::Corruption), - InvestState::InvestmentOngoing { invest_amount } => Err(DispatchError::Corruption), + InvestState::NoState | InvestState::InvestmentOngoing { ..} => Err(DispatchError::Other("Invalid pre state when transitioning a fulfilled order")), // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Self::ensure_currencies_match(true, &swap, pool_swap)?; + if swap.amount == pool_swap.amount { Ok(Self::InvestmentOngoing { invest_amount: swap.amount }) } else if swap.amount < pool_swap.amount { @@ -742,6 +744,8 @@ where }, // Increment done_return by swapped amount InvestState::ActiveSwapIntoReturnCurrency { swap: return_swap } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; + if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDone { swap }) } else if swap.amount < return_swap.amount { @@ -758,6 +762,7 @@ where }, // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + Self::ensure_currencies_match(true, &swap, pool_swap)?; let invest_amount = invest_amount.ensure_add(swap.amount)?; if swap.amount == pool_swap.amount { @@ -776,6 +781,8 @@ where }, // Increment done_return by swapped amount, leave invest amount untouched InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; + if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount: *invest_amount }) } else if swap.amount < return_swap.amount { @@ -792,6 +799,7 @@ where }, // Increment done_return by swapped amount InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: return_swap, done_amount } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { @@ -810,6 +818,7 @@ where }, // Increment done_return by swapped amount, leave invest amount untouched InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + Self::ensure_currencies_match(true, &swap, return_swap)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { @@ -826,92 +835,99 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) } }, - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Corruption), - // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in post - // transition trigger and thus never exist as pre transition state - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), - // Should be cleared entirely in post transition trigger and thus never exist as pre - // transition state - InvestState::SwapIntoReturnDone {.. } => Err(DispatchError::Corruption), - // Should be updated to `InvestmentOngoing` in post transition trigger and thus never - // exist as pre transition state - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Corruption), + _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone")) + } + } + + // TODO(@review): Do we need to handle this case at all or assume to always have + // required swaps through foreign investments? + + /// Handle increase transitions for the same incoming and outgoing + /// currencies. + /// + /// NOTE: We can ignore any state which involves an active swap, i.e. + /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the + /// in and out currency is the same. + fn handle_increase_non_foreign( + &self, + swap: Swap, + ) -> Result { + match &self { + Self::NoState => Ok(Self::InvestmentOngoing { + invest_amount: swap.amount, + }), + Self::InvestmentOngoing { invest_amount } => Ok(Self::InvestmentOngoing { + invest_amount: invest_amount.ensure_add(swap.amount)?, + }), + Self::ActiveSwapIntoPoolCurrency { .. } | + Self::ActiveSwapIntoReturnCurrency { .. } | + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } | + Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { .. } | + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Other("Invalid pre state when transitioning an increased swap order with the same in- and outgoing currency")), + _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone")) } } // TODO(@review): Do we need to handle this case at all or assume to always have // required swaps through foreign investments? - // fn handle_increase_non_foreign(&self, swap: Swap) -> - // Result { match &self { - // Self::NoState => { - // Ok(Self::InvestmentOngoing { - // invest_amount: swap.amount, - // }) - // } - // Self::InvestmentOngoing { invest_amount } => { - // Ok(Self::InvestmentOngoing { - // invest_amount: invest_amount.ensure_add(swap.amount)?, - // }) - // } - // Self::ActiveSwapIntoPoolCurrency { ..} => todo!(), - // Self::ActiveSwapIntoReturnCurrency { ..} => todo!(), - // Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - // swap, - // invest_amount, - // } => todo!(), - // Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - // swap, - // invest_amount, - // } => todo!(), - // Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } - // => todo!(), Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, - // done_amount } => { todo!() - // } - // Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - // swap, - // done_amount, - // invest_amount, - // } => todo!(), - // Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - // swap, - // done_amount, - // invest_amount, - // } => todo!(), - // Self::SwapIntoReturnDone(done_swap) => { - // if swap.currency_in == swap.currency_out { - // if swap.amount < done_swap.amount { - // Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { - // swap: Swap { - // currency_in: swap.currency_out, - // currency_out: swap.currency_in, - // amount: done_swap.amount.ensure_sub(swap.amount)?, - // }, - // invest_amount: swap.amount, - // }) - // } else { - // Ok(Self::InvestmentOngoing { - // invest_amount: swap.amount, - // }) - // } - // } else { - // if swap.amount < done_swap.amount { - // let done_amount = done_swap.amount.ensure_sub(swap.amount)?; - // Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { - // swap, - // done_amount, - // }) - // } else { - // Ok(Self::ActiveSwapIntoPoolCurrency { swap }) - // } - // } - // } - // Self::SwapIntoReturnDoneAndInvestmentOngoing { - // swap, - // invest_amount, - // } => todo!(), - // } + + /// Handle decrease transitions for the same incoming and outgoing + /// currencies. + /// + /// NOTE: We can ignore any state which involves an active swap, i.e. + /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the + /// in and out currency is the same. + fn handle_decrease_non_foreign( + &self, + swap: Swap, + ) -> Result { + if let Self::InvestmentOngoing { invest_amount } = &self { + if swap.amount < *invest_amount { + Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { + swap, + invest_amount: invest_amount.ensure_sub(swap.amount)?, + }) + } else { + Ok(Self::SwapIntoReturnDone { swap }) + } + } + // should never occur but let's be safe here + else { + Err(DispatchError::Other("Invalid pre state when transitioning a decreased swap order with the same in- and outgoing currency")) + } + } + + // TODO(@review): Can we ensure this check at an earlier stage? + + /// Ensures that the ingoing and outgoing currencies of two swaps + /// * Either match fully (in is in, out is out) if the swap direction is + /// the same for both swaps, i.e. (pool, pool) or (return, return) + /// * Or the ingoing and outgoing currencies match if the swap direction is + /// opposite, i.e. (pool, return) or (return, pool) + fn ensure_currencies_match( + is_same_swap_direction: bool, + swap_1: &Swap, + swap_2: &Swap, + ) -> DispatchResult { + if is_same_swap_direction + && swap_1.currency_in != swap_2.currency_in + && swap_1.currency_out != swap_2.currency_out + { + Err(DispatchError::Other( + "Swap currency mismatch for same swap direction", + )) + } else if !is_same_swap_direction + && swap_1.currency_in != swap_2.currency_out + && swap_1.currency_out != swap_2.currency_in + { + Err(DispatchError::Other( + "Swap currency mismatch for opposite swap direction", + )) + } else { + Ok(()) + } + } } // TODO: How to merge token swaps and investment trait? Create new trait From 8da787f255f73fc7f616db076697028353a452ba Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 20 Jul 2023 14:51:06 +0200 Subject: [PATCH 09/96] feat: add redemption states --- libs/traits/src/lib.rs | 48 +++-- pallets/foreign-investments/src/impls.rs | 61 +++++-- pallets/foreign-investments/src/types.rs | 213 ++++++++++++++++++++--- 3 files changed, 266 insertions(+), 56 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 5b4de44fb8..6018219812 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -735,16 +735,7 @@ pub trait ForeignInvestment { type Error: Debug; type InvestmentId; - type SwapNotification; - - // type Investment: Investment< - // AccountId, - // Amount = Self::Amount, - // CurrencyId = Self::CurrencyId, - // Error = Self::Error, - // InvestmentId = Self::InvestmentId, - // >; - + // TODO: Docs /// * Apply state transition /// * Kick off swap fn update_foreign_invest_order( @@ -755,13 +746,36 @@ pub trait ForeignInvestment { amount: Self::Amount, ) -> Result<(), Self::Error>; - // Do actual investment update after successful (partial) token swap - // * Triggered by SwapNotification - // fn finalize_update_investment( - // who: &AccountId, - // investment_id: Self::InvestmentId, - // amount: Self::Amount, - // ) -> Result<(), Self::Error>; + // TODO: Docs + fn update_foreign_redemption( + who: &AccountId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error> { + todo!() + } + + // TODO: Docs + fn collect_foreign_investment( + who: &AccountId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + ) -> Result<(), Self::Error> { + todo!() + } + + // TODO: Docs + fn collect_foreign_redemption( + who: &AccountId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + ) -> Result<(), Self::Error> { + todo!() + } } pub trait StatusNotificationHook { diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls.rs index cc134c398d..5a6bcf03f9 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls.rs @@ -62,7 +62,6 @@ impl ForeignInvestment for Pallet { type CurrencyId = T::CurrencyId; type Error = DispatchError; type InvestmentId = T::InvestmentId; - type SwapNotification = Pallet; // Consumers such as Connectors should call this function instead of // `Investment::update_invest_order` as this implementation accounts for @@ -99,7 +98,33 @@ impl ForeignInvestment for Pallet { Ok(()) } - // TODO: Add similar functions for redemptions and collections + fn update_foreign_redemption( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + amount: T::Balance, + ) -> Result<(), DispatchError> { + todo!() + } + + fn collect_foreign_investment( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + ) -> Result<(), DispatchError> { + todo!() + } + + fn collect_foreign_redemption( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + ) -> Result<(), DispatchError> { + todo!() + } } impl Pallet { @@ -161,21 +186,21 @@ impl Pallet { InvestmentState::::insert(who, investment_id, new_state); return Ok(()); }, - InvestState::SwapIntoReturnDone { swap } => { + InvestState::SwapIntoReturnDone { done_swap } => { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, Zero::zero())?; - Self::send_executed_decrease_hook(who, investment_id, swap.amount)?; + Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; // Exit early to prevent setting InvestmentState InvestmentState::::remove(who, investment_id); return Ok(()); }, - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount } => { + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { Self::kill_swap_order(who, investment_id)?; T::Investment::update_investment(who, investment_id, invest_amount)?; - Self::send_executed_decrease_hook(who, investment_id, swap.amount)?; + Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; // Exit early to prevent setting InvestmentState let new_state = InvestState::InvestmentOngoing { invest_amount }; @@ -383,7 +408,7 @@ where // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - swap: *return_swap, + done_swap: *return_swap, invest_amount, }) } @@ -444,7 +469,7 @@ where // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - swap: *return_swap, + done_swap: *return_swap, invest_amount, }) } @@ -476,7 +501,7 @@ where // pool swap amount is immediately invested and done amount increased equally if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { + done_swap: Swap { amount: done_amount, ..*return_swap }, @@ -524,7 +549,7 @@ where // pool swap amount is immediately invested and done amount increased equally if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { + done_swap: Swap { amount: done_amount, ..*return_swap }, @@ -604,7 +629,7 @@ where Self::ensure_currencies_match(false, &swap, pool_swap)?; if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDone { swap }) + Ok(Self::SwapIntoReturnDone { done_swap: swap }) } else if swap.amount < pool_swap.amount { Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: Swap { // safe because swap.amount < pool_swap.amount @@ -631,7 +656,7 @@ where ..*pool_swap }, done_amount, invest_amount }) } else if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount }) + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: swap, invest_amount }) } else if swap.amount < max_decrease_amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { // safe because done_amount is min @@ -747,7 +772,7 @@ where Self::ensure_currencies_match(true, &swap, return_swap)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDone { swap }) + Ok(Self::SwapIntoReturnDone { done_swap: swap }) } else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { // safe because return_swap.amount > swap.amount @@ -784,7 +809,7 @@ where Self::ensure_currencies_match(true, &swap, return_swap)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap, invest_amount: *invest_amount }) + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: swap, invest_amount: *invest_amount }) } else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { // safe because return_swap.amount > swap.amount @@ -803,7 +828,7 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDone { swap: Swap { amount: done_amount, ..swap } }) + Ok(Self::SwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) } else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { // safe because return_swap.amount > swap.amount @@ -822,7 +847,7 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount: done_amount, ..swap }, invest_amount: *invest_amount }) + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, ..swap }, invest_amount: *invest_amount }) } else if swap.amount < return_swap.amount { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing{ swap: Swap { // safe because return_swap.amount > swap.amount @@ -885,11 +910,11 @@ where if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { - swap, + done_swap: swap, invest_amount: invest_amount.ensure_sub(swap.amount)?, }) } else { - Ok(Self::SwapIntoReturnDone { swap }) + Ok(Self::SwapIntoReturnDone { done_swap: swap }) } } // should never occur but let's be safe here diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 06709c0ef3..835f6a39ac 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -35,9 +35,10 @@ pub struct Swap::Investment`. This includes swapping it +/// into a pool currency or back, if the investment is decreased before it is +/// fully processed. #[derive( Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] @@ -46,6 +47,8 @@ pub enum InvestState< Currency: Clone + Copy + PartialEq, > { #[default] + /// Placeholder state for initialization which will never be stored on + /// chain. NoState, /// The investment is waiting to be processed. InvestmentOngoing { invest_amount: Balance }, @@ -55,24 +58,24 @@ pub enum InvestState< /// back into the corresponding return currency. ActiveSwapIntoReturnCurrency { swap: Swap }, /// The investment is not fully swapped into pool currency and thus split - /// into two: + /// into two parts: /// * One part is still being swapped. - /// * The other part is already waiting to be processed as investment. + /// * The remainder is already waiting to be processed as investment. ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap, invest_amount: Balance, }, - /// The investment is split into two: + /// The investment is split into two parts: /// * One part is waiting to be processed as investment. - /// * The other part is swapped back into the return currency as a - /// result of decreasing the invested amount before being processed. + /// * The remainder is swapped back into the return currency as a result + /// of decreasing the invested amount before being processed. ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: Swap, invest_amount: Balance, }, - /// The investment is split into two: + /// The investment is split into two parts: /// * The one part is swapping into pool currency. - /// * The other part was swapped back into the return currency as a + /// * The remainder was swapped back into the return currency as a /// result of decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into `ActiveSwapIntoPoolCurrency` @@ -87,10 +90,10 @@ pub enum InvestState< swap: Swap, done_amount: Balance, }, - /// The investment is split into three: + /// The investment is split into three parts: /// * One part is currently swapping into the pool currency. - /// * The second part is already waiting to be processed as investment. - /// * The remaining part was swapped back into the return currency as a + /// * The second is already waiting to be processed as investment. + /// * The remainder was swapped back into the return currency as a /// result of decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into @@ -101,12 +104,11 @@ pub enum InvestState< done_amount: Balance, invest_amount: Balance, }, - /// The investment is split into three: + /// The investment is split into three parts: /// * One is waiting to be processed as investment. - /// * The second part is swapped back into the return currency as a - /// result of decreasing the invested amount before being processed. - /// * The remaining part was already swapped back into the return - /// currency. + /// * The second is swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. + /// * The remainder was already swapped back into the return currency. /// /// NOTE: This state should not be transitioned by applying the trigger for /// the done part but wait until the active swap is fulfilled. @@ -119,8 +121,8 @@ pub enum InvestState< /// /// NOTE: This state can be killed by applying the corresponding trigger to /// handle the return amount. - SwapIntoReturnDone { swap: Swap }, - /// The investment is split into two: + SwapIntoReturnDone { done_swap: Swap }, + /// The investment is split into two parts: /// * One part is waiting to be processed as an investment /// * The swapped back into the return currency as a result of /// decreasing the invested amount before being processed. @@ -128,7 +130,7 @@ pub enum InvestState< /// NOTE: This state can be transitioned into `InvestmentOngoing` by /// applying the corresponding trigger to handle the return amount. SwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap, + done_swap: Swap, invest_amount: Balance, }, } @@ -150,3 +152,172 @@ pub enum InvestTransition< /// `currency_in` is the return currency. FulfillSwapOrder(Swap), } + +/// Reflects all states a foreign redemption can have until transferred to the +/// corresponding source domain. +/// +/// This includes swapping it into a pool currency or back, if the investment is +/// decreased before it is fully processed. +#[derive( + Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] +pub enum RedeemState< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +> { + #[default] + /// Placeholder state for initialization which will never be stored on + /// chain. + NoState, + /// There is no pending redemption process at this point. The investment can + /// be redeemed up to the invested amount (after fulfillment). + Invested { invest_amount: Balance }, + /// There is no remaining investment such that the redemption cannot be + /// increased at this point. + NotInvestedAnd(InnerRedeemState), + /// There is a remaining invested amount such that the redemption can be + /// increased up to the remaining invested amount (after fulfillment). + InvestedAnd(InnerRedeemState), +} + +/// Reflects all possible redeem states independent of whether an investment is +/// still active or not in the actual `RedeemState`. +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub enum InnerRedeemState< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +> { + /// The redemption is pending until it is processed during epoch execution. + Redeeming { redeem_amount: Balance }, + /// The redemption was fully processed and must be collected before it can + /// be transferred back. + CollectableRedemption { collect_amount: Balance }, + /// The redemption was partially processed and is split into a pending + /// redemption and a collectable amount. + RedeemingAndCollectableRedemption { + redeem_amount: Balance, + collect_amount: Balance, + }, + /// The redemption was fully processed and collected and is currently + /// swapping into the return currency. + ActiveSwapIntoReturnCurrency { swap: Swap }, + /// The redemption was fully processed, collected and partially swapped into + /// the return currency. It is split into two parts: + /// * One part is swapping back into the return currency. + /// * The remainder was already swapped back. + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap, + done_amount: Balance, + }, + /// The redemption was fully processed, collected and swapped into the + /// return currency. + /// + /// NOTE: This state does not require handling in `RedeemState::transition` + /// as it must be manually transitioned in `apply_state_transition`, similar + /// to the corresponding state in `InvestState`. + SwapIntoReturnDone { done_swap: Swap }, + /// The redemption is split into two parts: + /// * One part is waiting to be processed as redemption. + /// * The remainder is swapping back into the return currency as a + /// result of processing and collecting beforehand. + RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount: Balance, + swap: Swap, + }, + /// The redemption is split into two parts: + /// * One part is waiting to be processed as redemption. + /// * The remainder is swapping back into the return currency as a + /// result of processing and collecting beforehand. + RedeemingAndSwapIntoReturnDone { + redeem_amount: Balance, + done_swap: Swap, + }, + /// The redemption is split into three parts: + /// * One part is waiting to be processed as redemption. + /// * The second is swapping back into the return currency as a result + /// of processing and collecting beforehand. + /// * The remainder was already swapped back. + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount: Balance, + swap: Swap, + done_amount: Balance, + }, + /// The redemption is split into three parts: + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The remainder is swapping back into the return currency as a + /// result of processing and collecting beforehand. + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + redeem_amount: Balance, + collect_amount: Balance, + swap: Swap, + }, + /// The redemption is split into three parts: + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The remainder was successfully swapped back into the return + /// currency as a result of processing and collecting beforehand. + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + redeem_amount: Balance, + collect_amount: Balance, + done_swap: Swap, + }, + /// The redemption is split into four parts: + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The third part is swapping back into the return currency as a result + /// of processing and collecting beforehand + /// * The remainder was already swapped back. + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount: Balance, + collect_amount: Balance, + swap: Swap, + done_amount: Balance, + }, + /// The redemption is split into two parts: + /// * One part is waiting to be collected. + /// * The remainder is swapping back into the return currency as a + /// result of processing and collecting beforehand. + CollectableRedemptionAndActiveSwapIntoReturnCurrency { + collect_amount: Balance, + swap: Swap, + }, + /// The redemption is split into two parts: + /// * One part is waiting to be collected. + /// * The remainder was successfully swapped back into the return + /// currency as a result of processing and collecting beforehand. + CollectableRedemptionAndSwapIntoReturnDone { + collect_amount: Balance, + done_swap: Swap, + }, + /// The redemption is split into three parts: + /// * One part is waiting to be collected. + /// * The second is swapping back into the return currency as a result of + /// processing and collecting beforehand + /// * The remainder was already swapped back. + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + collect_amount: Balance, + swap: Swap, + done_amount: Balance, + }, +} + +// // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in +// post // transition trigger and thus never exist as pre transition state +// Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => { +// Err(DispatchError::Other("Invalid pre state, should automatically be +// transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) } +// // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in +// post // transition trigger and thus never exist as pre transition state +// Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { +// .. +// } => Err(DispatchError::Other("Invalid pre state, should automatically be +// transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")), // +// Should be cleared entirely in post transition trigger and thus never exist as +// pre // transition state Self::SwapIntoReturnDone { .. } => +// Err(DispatchError::Other("Invalid pre state, should automatically be +// transitioned into NoState")), // Should be updated to `InvestmentOngoing` in +// post transition trigger and thus never // exist as pre transition state +// Self::SwapIntoReturnDoneAndInvestmentOngoing { .. } => +// Err(DispatchError::Other("Invalid pre state, should automatically be +// transitioned into InvestmentOngoing")), From 4828d1261d34791c2ac1b885944f3550c75b67c9 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 26 Jul 2023 20:48:57 +0200 Subject: [PATCH 10/96] feat: handle concurrent swap orders --- libs/traits/src/lib.rs | 5 +- pallets/connectors/src/inbound.rs | 7 + .../foreign-investments/src/delete_impls.rs | 70 ++ .../src/{impls.rs => impls/invest.rs} | 761 +++++++----------- pallets/foreign-investments/src/impls/mod.rs | 575 +++++++++++++ .../foreign-investments/src/impls/redeem.rs | 361 +++++++++ pallets/foreign-investments/src/lib.rs | 56 +- pallets/foreign-investments/src/types.rs | 52 +- 8 files changed, 1407 insertions(+), 480 deletions(-) create mode 100644 pallets/foreign-investments/src/delete_impls.rs rename pallets/foreign-investments/src/{impls.rs => impls/invest.rs} (56%) create mode 100644 pallets/foreign-investments/src/impls/mod.rs create mode 100644 pallets/foreign-investments/src/impls/redeem.rs diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 6018219812..1aec99e3be 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -749,8 +749,9 @@ pub trait ForeignInvestment { // TODO: Docs fn update_foreign_redemption( who: &AccountId, - return_currency: Self::CurrencyId, - pool_currency: Self::CurrencyId, + // TODO: Check if we do not require them if can be derived in CollectRedeemOrder + // return_currency: Self::CurrencyId, + // pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, amount: Self::Amount, ) -> Result<(), Self::Error> { diff --git a/pallets/connectors/src/inbound.rs b/pallets/connectors/src/inbound.rs index 7feed8157d..8879a1f908 100644 --- a/pallets/connectors/src/inbound.rs +++ b/pallets/connectors/src/inbound.rs @@ -103,6 +103,7 @@ impl Pallet { // Mint additional amount T::Tokens::mint_into(currency, &investor, amount)?; + // TODO: Apply pallet_foreign_investment::ForeignInvestment T::ForeignInvestment::update_investment(&investor, invest_id, post_amount)?; Ok(()) @@ -129,6 +130,7 @@ impl Pallet { let pre_amount = T::ForeignInvestment::investment(&investor, invest_id.clone())?; let post_amount = pre_amount.ensure_sub(amount)?; + // TODO: Apply pallet_foreign_investment::ForeignInvestment T::ForeignInvestment::update_investment(&investor, invest_id, post_amount)?; // TODO: Handle response `ExecutedDecreaseInvestOrder` message to @@ -164,6 +166,8 @@ impl Pallet { // Determine post adjustment amount let pre_amount = T::ForeignInvestment::redemption(&investor, invest_id.clone())?; + + // TODO: Apply pallet_foreign_investment::ForeignInvestment let post_amount = pre_amount.ensure_add(amount)?; // Transfer tranche tokens from `DomainLocator` account of origination domain @@ -203,6 +207,7 @@ impl Pallet { let pre_amount = T::ForeignInvestment::redemption(&investor, invest_id.clone())?; let post_amount = pre_amount.ensure_sub(amount)?; + // TODO: Apply pallet_foreign_investment::ForeignInvestment T::ForeignInvestment::update_redemption(&investor, invest_id, post_amount)?; // TODO: Handle response `ExecutedDecreaseRedemption` message to @@ -229,6 +234,7 @@ impl Pallet { ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + // TODO: Apply pallet_foreign_investment::ForeignInvestment T::ForeignInvestment::collect_investment(investor, invest_id)?; // TODO: Handle response `ExecutedCollectInvest` message to @@ -251,6 +257,7 @@ impl Pallet { ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + // TODO: Apply pallet_foreign_investment::ForeignInvestment T::ForeignInvestment::collect_redemption(investor, invest_id)?; // TODO: Handle response `ExecutedCollectRedeem` message to diff --git a/pallets/foreign-investments/src/delete_impls.rs b/pallets/foreign-investments/src/delete_impls.rs new file mode 100644 index 0000000000..df5c2536f4 --- /dev/null +++ b/pallets/foreign-investments/src/delete_impls.rs @@ -0,0 +1,70 @@ +// TODO: How to merge token swaps and investment trait? Create new trait +// ForeignInvestment? > Check diagrams + +// impl Investment for Pallet { +// type Amount = T::Balance; +// type CurrencyId = T::CurrencyId; +// type Error = DispatchError; +// type InvestmentId = T::InvestmentId; + +// fn update_investment( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// amount: Self::Amount, +// ) -> Result<(), Self::Error> { +// let pre_amount = Self::investment(who, investment_id.clone())?; +// let pre_state = InvestmentState::::get(who, +// investment_id.clone()).unwrap_or_default(); + +// if amount > pre_amount { +// // TODO: Can payment currency be derived? +// let swap_currency = +// ::info(investment_id).map(|info| +// info.payment_currency()); let post_state: Option::Balance, ::CurrencyId>> = pre_state. +// transition(InvestTransition::IncreaseInvestOrder(amount))?; Ok(()) +// } else if amount < pre_amount { +// let post_state: Option::Balance, ::CurrencyId>> = pre_state. +// transition(InvestTransition::DecreaseInvestOrder(amount))?; Ok(()) +// } else { +// Ok(()) +// } +// } + +// fn accepted_payment_currency( +// investment_id: Self::InvestmentId, +// currency: Self::CurrencyId, +// ) -> bool { +// T::Investment::accepted_payment_currency(investment_id, currency) +// } + +// fn investment( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// ) -> Result { +// todo!() +// } + +// fn update_redemption( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// amount: Self::Amount, +// ) -> Result<(), Self::Error> { +// todo!() +// } + +// fn accepted_payout_currency( +// investment_id: Self::InvestmentId, +// currency: Self::CurrencyId, +// ) -> bool { +// T::Investment::accepted_payout_currency(investment_id, currency) +// } + +// fn redemption( +// who: &T::AccountId, +// investment_id: Self::InvestmentId, +// ) -> Result { +// todo!() +// } +// } diff --git a/pallets/foreign-investments/src/impls.rs b/pallets/foreign-investments/src/impls/invest.rs similarity index 56% rename from pallets/foreign-investments/src/impls.rs rename to pallets/foreign-investments/src/impls/invest.rs index 5a6bcf03f9..80bd2f06e5 100644 --- a/pallets/foreign-investments/src/impls.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -11,285 +11,12 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; -use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; -use frame_support::{traits::Get, transactional}; use sp_runtime::{ - traits::{EnsureAdd, EnsureSub, Zero}, + traits::{EnsureAdd, EnsureSub}, ArithmeticError, DispatchError, DispatchResult, }; -use crate::{ - pallet, - types::{InvestState, InvestTransition, Swap}, - Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, SwapOf, - TokenSwapOrderIds, -}; - -// Handles the second stage of updating investments. Whichever (potentially -// async) code path of the first stage concludes it (partially) should call -// `Swap::Config::SwapNotificationHandler::notify_status_update(swap_order_id, -// swapped_amount)`. -impl StatusNotificationHook for Pallet { - type Error = DispatchError; - type Id = T::TokenSwapOrderId; - type Status = SwapOf; - - fn notify_status_change( - id: T::TokenSwapOrderId, - status: SwapOf, - ) -> Result<(), DispatchError> { - let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; - let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); - - let post_state = pre_state.transition(InvestTransition::FulfillSwapOrder(status)) - .map_err(|e| { - log::debug!("Encountered unexpected pre state {:?} when transitioning into {:?} after (partially) fulfilling a swap", pre_state, status); - e - })?; - Pallet::::apply_state_transition(&info.owner, info.id, post_state.clone()).map(|e| { - log::debug!( - "Encountered unexpected error when applying state transition to state {:?}", - post_state - ); - e - }) - } -} - -impl ForeignInvestment for Pallet { - type Amount = T::Balance; - type CurrencyId = T::CurrencyId; - type Error = DispatchError; - type InvestmentId = T::InvestmentId; - - // Consumers such as Connectors should call this function instead of - // `Investment::update_invest_order` as this implementation accounts for - // (potentially) splitting the update into two stages. The second stage is - // resolved by `StatusNotificationHook::notify_status_change`. - fn update_foreign_invest_order( - who: &T::AccountId, - return_currency: T::CurrencyId, - pool_currency: T::CurrencyId, - investment_id: T::InvestmentId, - amount: T::Balance, - ) -> Result<(), DispatchError> { - let pre_amount = T::Investment::investment(who, investment_id.clone())?; - let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); - - let post_state = if amount > pre_amount { - pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { - currency_in: pool_currency, - currency_out: return_currency, - amount, - })) - } else if amount < pre_amount { - pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { - currency_in: return_currency, - currency_out: pool_currency, - amount, - })) - } else { - Ok(pre_state) - }?; - - Pallet::::apply_state_transition(who, investment_id, post_state)?; - - Ok(()) - } - - fn update_foreign_redemption( - who: &T::AccountId, - return_currency: T::CurrencyId, - pool_currency: T::CurrencyId, - investment_id: T::InvestmentId, - amount: T::Balance, - ) -> Result<(), DispatchError> { - todo!() - } - - fn collect_foreign_investment( - who: &T::AccountId, - return_currency: T::CurrencyId, - pool_currency: T::CurrencyId, - investment_id: T::InvestmentId, - ) -> Result<(), DispatchError> { - todo!() - } - - fn collect_foreign_redemption( - who: &T::AccountId, - return_currency: T::CurrencyId, - pool_currency: T::CurrencyId, - investment_id: T::InvestmentId, - ) -> Result<(), DispatchError> { - todo!() - } -} - -impl Pallet { - /// Must be called after transitioning any `InvestState` via `transition` to - /// update the chain storage and execute various trait config hooks, e.g. - /// `ExecutedDecreaseHook`. - #[transactional] - fn apply_state_transition( - who: &T::AccountId, - investment_id: T::InvestmentId, - state: InvestState, - ) -> DispatchResult { - match state.clone() { - InvestState::NoState=> { - Self::kill_swap_order(who, investment_id)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - - // Exit early to prevent setting InvestmentState - InvestmentState::::remove(who, investment_id); - return Ok(()); - }, - InvestState::InvestmentOngoing { invest_amount } => { - Self::kill_swap_order(who, investment_id)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - }, - InvestState::ActiveSwapIntoPoolCurrency { swap } | - InvestState::ActiveSwapIntoReturnCurrency { swap } | - // We don't care about `done_amount` until swap into return is fulfilled - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { - Self::place_swap_order(who, investment_id, swap)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - }, - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | - // We don't care about `done_amount` until swap into return is fulfilled - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { - Self::place_swap_order(who, investment_id, swap)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - }, - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::place_swap_order(who, investment_id, swap.clone())?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - - // Exit early to prevent setting InvestmentState - let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; - InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); - }, - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::place_swap_order(who, investment_id, swap.clone())?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - - // Exit early to prevent setting InvestmentState - let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); - }, - InvestState::SwapIntoReturnDone { done_swap } => { - Self::kill_swap_order(who, investment_id)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; - - // Exit early to prevent setting InvestmentState - InvestmentState::::remove(who, investment_id); - return Ok(()); - }, - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { - Self::kill_swap_order(who, investment_id)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; - - // Exit early to prevent setting InvestmentState - let new_state = InvestState::InvestmentOngoing { invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); - }, - }; - - InvestmentState::::insert(who, investment_id, state); - - // TODO: Emit event? - - Ok(()) - } - - /// Kills all storage associated with token swaps and cancels the - /// potentially active swap order. - fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { - if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { - T::TokenSwaps::cancel_order(swap_order_id); - ForeignInvestmentInfo::::remove(swap_order_id); - } - Ok(()) - } - - /// Initializes or updates an existing swap order. - /// - /// Sets up `TokenSwapOrderIds` and `ForeignInvestmentInfo` storages, if the - /// order does not exist yet. - fn place_swap_order( - who: &T::AccountId, - investment_id: T::InvestmentId, - swap: SwapOf, - ) -> DispatchResult { - if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { - T::TokenSwaps::update_order( - who.clone(), - swap_order_id, - swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), - ) - } else { - // TODO: How to handle potential failure? - let order_id = T::TokenSwaps::place_order( - who.clone(), - swap.currency_out, - swap.currency_in, - swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), - )?; - TokenSwapOrderIds::::insert(who, investment_id, order_id); - ForeignInvestmentInfo::::insert( - order_id, - ForeignInvestmentInfoOf:: { - owner: who.clone(), - id: investment_id, - }, - ); - Ok(()) - } - } - - /// Sends `ExecutedDecreaseHook` notification such that any potential - /// consumer could act upon that, e.g. Connectors for - /// `ExecutedDecrease{Invest, Redeem}Order`. - fn send_executed_decrease_hook( - who: &T::AccountId, - investment_id: T::InvestmentId, - amount_payout: T::Balance, - ) -> DispatchResult { - // TODO(@mustermeiszer): Does this return the entire desired amount or do we - // need to tap into collecting? - let amount_remaining = T::Investment::investment(who, investment_id)?; - - // TODO(@mustermeiszer): Do we add the active swap amount? - T::ExecutedDecreaseHook::notify_status_change( - ForeignInvestmentInfoOf:: { - owner: who.clone(), - id: investment_id, - }, - ExecutedDecrease { - amount_payout, - amount_remaining, - }, - ) - } -} +use crate::types::{InvestState, InvestTransition, Swap}; impl InvestState where @@ -313,6 +40,33 @@ where } } } + + /// Returns the potentially existing active swap into either return or pool + /// currency: + /// + /// * If the state includes `ActiveSwapInto{Pool, Return}Currency`, it + /// returns `Some(swap)`. + /// * Else, it returns `None`. + pub(crate) fn get_active_swap(&self) -> Option> { + match *self { + InvestState::NoState => None, + InvestState::InvestmentOngoing { .. } => None, + InvestState::ActiveSwapIntoPoolCurrency { swap } => Some(swap), + InvestState::ActiveSwapIntoReturnCurrency { swap } => Some(swap), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, .. } => { + Some(swap) + }, + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, .. } => { + Some(swap) + }, + InvestState::SwapIntoReturnDone { .. } => None, + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => None, + } + } } // Actual impl of transition @@ -395,15 +149,17 @@ where // pool swap amount is immediately invested and done amount increased equally if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }) + ) } // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { @@ -435,14 +191,13 @@ where Self::ensure_currencies_match(true, &swap, pool_swap)?; Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: swap.amount.ensure_add(pool_swap.amount)?, - ..swap - }, - invest_amount: *invest_amount, - } - ) - }, + swap: Swap { + amount: swap.amount.ensure_add(pool_swap.amount)?, + ..swap + }, + invest_amount: *invest_amount, + }) + } // Reduce return swap amount by the increasing amount and increase investing amount as // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { @@ -456,15 +211,17 @@ where // pool swap amount is immediately invested and done amount increased equally if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }) + ) } // swap amount is immediately invested and done amount increased equally else if swap.amount == return_swap.amount { @@ -510,11 +267,17 @@ where } // swap amount is immediately invested and done amount increased equally else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, done_amount, invest_amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }, + ) } // return swap amount is immediately invested and done amount increased equally else { @@ -558,11 +321,17 @@ where } // swap amount is immediately invested and done amount increased equally else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap - }, done_amount, invest_amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, + }, + ) } // return swap amount is immediately invested and done amount increased equally else { @@ -579,7 +348,10 @@ where ) } } - _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) + _ => Err(DispatchError::Other( + "Invalid pre state, should automatically be transitioned into \ + ActiveSwapIntoPoolCurrencyAndInvestmentOngoing", + )), } } @@ -611,11 +383,18 @@ where match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::NoState | InvestState::ActiveSwapIntoReturnCurrency { .. } | InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Err(DispatchError::Other("Invalid pre state when transitioning a decrease")), + InvestState::NoState + | InvestState::ActiveSwapIntoReturnCurrency { .. } + | InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => { + Err(DispatchError::Other("Invalid pre state when transitioning a decrease")) + }, // Increment return swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount: *invest_amount - swap.amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap, + invest_amount: *invest_amount - swap.amount, + }) } else if swap.amount == *invest_amount { Ok(Self::ActiveSwapIntoReturnCurrency { swap }) } @@ -631,11 +410,14 @@ where if swap.amount == pool_swap.amount { Ok(Self::SwapIntoReturnDone { done_swap: swap }) } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap: Swap { - // safe because swap.amount < pool_swap.amount - amount: pool_swap.amount - swap.amount, - ..*pool_swap - }, done_amount: swap.amount}) + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because swap.amount < pool_swap.amount + amount: pool_swap.amount - swap.amount, + ..*pool_swap + }, + done_amount: swap.amount, + }) } // should never occur but let's be safe here else { @@ -643,32 +425,53 @@ where } }, // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: pool_swap, + invest_amount, + } => { Self::ensure_currencies_match(false, &swap, pool_swap)?; let done_amount = swap.amount.min(pool_swap.amount); let invest_amount = invest_amount.ensure_sub(done_amount)?; let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe because done_amount is min - amount: pool_swap.amount - done_amount, - ..*pool_swap - }, done_amount, invest_amount }) - } else if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: swap, invest_amount }) + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because done_amount is min + amount: pool_swap.amount - done_amount, + ..*pool_swap + }, + done_amount, + invest_amount, + }, + ) + } else if swap.amount == pool_swap.amount { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap: swap, + invest_amount, + }) } else if swap.amount < max_decrease_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe because done_amount is min - amount: swap.amount - done_amount, - ..swap - }, done_amount, invest_amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because done_amount is min + amount: swap.amount - done_amount, + ..swap + }, + done_amount, + invest_amount, + }, + ) } else if swap.amount == max_decrease_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - // safe because done_amount is min - amount: swap.amount - done_amount, - ..swap - }, done_amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because done_amount is min + amount: swap.amount - done_amount, + ..swap + }, + done_amount, + }) } // should never occur but let's be safe here else { @@ -676,47 +479,62 @@ where } }, // Increment return swap up to ongoing investment - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap: return_swap, + invest_amount, + } => { Self::ensure_currencies_match(true, &swap, return_swap)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: Swap { - amount, - ..swap - }, - // safe because invest_amount > swap_amount - invest_amount: *invest_amount - swap.amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap: Swap { amount, ..swap }, + // safe because invest_amount > swap_amount + invest_amount: *invest_amount - swap.amount, + }) } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrency { swap: Swap { - amount, - ..swap - } }) + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: Swap { amount, ..swap }, + }) } // should never occur but let's be safe here else { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: return_swap, + done_amount, + invest_amount, + } => { Self::ensure_currencies_match(true, &swap, return_swap)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { amount, ..swap}, done_amount: *done_amount, - // safe because swap.amount < invest_amount - invest_amount: *invest_amount - swap.amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { amount, ..swap }, + done_amount: *done_amount, + // safe because swap.amount < invest_amount + invest_amount: *invest_amount - swap.amount, + }, + ) } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount, ..swap}, done_amount: *done_amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { amount, ..swap }, + done_amount: *done_amount, + }) } // should never occur but let's be safe here else { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) - - } + _ => Err(DispatchError::Other( + "Invalid pre state, should automatically be transitioned into \ + ActiveSwapIntoPoolCurrencyAndInvestmentOngoing", + )), + } } /// Handle partial/full token swap order transitions depicted by @@ -748,19 +566,26 @@ where swap: Swap, ) -> Result { match &self { - InvestState::NoState | InvestState::InvestmentOngoing { ..} => Err(DispatchError::Other("Invalid pre state when transitioning a fulfilled order")), + InvestState::NoState | InvestState::InvestmentOngoing { .. } => Err(DispatchError::Other( + "Invalid pre state when transitioning a fulfilled order", + )), // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { Self::ensure_currencies_match(true, &swap, pool_swap)?; if swap.amount == pool_swap.amount { - Ok(Self::InvestmentOngoing { invest_amount: swap.amount }) + Ok(Self::InvestmentOngoing { + invest_amount: swap.amount, + }) } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, - ..swap - }, invest_amount: swap.amount }) + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, + ..swap + }, + invest_amount: swap.amount, + }) } // should never occur but let's be safe here else { @@ -774,11 +599,14 @@ where if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDone { done_swap: swap }) } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, done_amount: swap.amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount: swap.amount, + }) } // should never occur but let's be safe here else { @@ -786,18 +614,24 @@ where } }, // Increment ongoing investment by swapped amount - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount } => { + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: pool_swap, + invest_amount, + } => { Self::ensure_currencies_match(true, &swap, pool_swap)?; let invest_amount = invest_amount.ensure_add(swap.amount)?; if swap.amount == pool_swap.amount { Ok(Self::InvestmentOngoing { invest_amount }) } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, - ..swap - }, invest_amount }) + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, + ..swap + }, + invest_amount, + }) } // should never occur but let's be safe here else { @@ -805,17 +639,29 @@ where } }, // Increment done_return by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: return_swap, invest_amount } => { + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap: return_swap, + invest_amount, + } => { Self::ensure_currencies_match(true, &swap, return_swap)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: swap, invest_amount: *invest_amount }) + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap: swap, + invest_amount: *invest_amount, + }) } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, done_amount: swap.amount, invest_amount: *invest_amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount: swap.amount, + invest_amount: *invest_amount, + }, + ) } // should never occur but let's be safe here else { @@ -823,18 +669,29 @@ where } }, // Increment done_return by swapped amount - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: return_swap, done_amount } => { + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: return_swap, + done_amount, + } => { Self::ensure_currencies_match(true, &swap, return_swap)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) + Ok(Self::SwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..swap + }, + }) } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, done_amount }) + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount, + }) } // should never occur but let's be safe here else { @@ -842,25 +699,43 @@ where } }, // Increment done_return by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: return_swap, done_amount, invest_amount } => { + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: return_swap, + done_amount, + invest_amount, + } => { Self::ensure_currencies_match(true, &swap, return_swap)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, ..swap }, invest_amount: *invest_amount }) + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap: Swap { + amount: done_amount, + ..swap + }, + invest_amount: *invest_amount, + }) } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing{ swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, done_amount, invest_amount: *invest_amount }) + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount, + invest_amount: *invest_amount, + }, + ) } // should never occur but let's be safe here else { Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) } }, - _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone")) + _ => Err(DispatchError::Other( + "Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone", + )), } } @@ -884,13 +759,21 @@ where Self::InvestmentOngoing { invest_amount } => Ok(Self::InvestmentOngoing { invest_amount: invest_amount.ensure_add(swap.amount)?, }), - Self::ActiveSwapIntoPoolCurrency { .. } | - Self::ActiveSwapIntoReturnCurrency { .. } | - Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } | - Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { .. } | - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Other("Invalid pre state when transitioning an increased swap order with the same in- and outgoing currency")), - _ => Err(DispatchError::Other("Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone")) + Self::ActiveSwapIntoPoolCurrency { .. } + | Self::ActiveSwapIntoReturnCurrency { .. } + | Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } + | Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { .. } + | Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } + | Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + .. + } => Err(DispatchError::Other( + "Invalid pre state when transitioning an increased swap order with the same in- \ + and outgoing currency", + )), + _ => Err(DispatchError::Other( + "Invalid pre state, should automatically be transitioned into state without \ + AndSwapIntoReturnDone", + )), } } @@ -919,7 +802,10 @@ where } // should never occur but let's be safe here else { - Err(DispatchError::Other("Invalid pre state when transitioning a decreased swap order with the same in- and outgoing currency")) + Err(DispatchError::Other( + "Invalid pre state when transitioning a decreased swap order with the same in- \ + and outgoing currency", + )) } } @@ -954,74 +840,3 @@ where } } } - -// TODO: How to merge token swaps and investment trait? Create new trait -// ForeignInvestment? > Check diagrams - -// impl Investment for Pallet { -// type Amount = T::Balance; -// type CurrencyId = T::CurrencyId; -// type Error = DispatchError; -// type InvestmentId = T::InvestmentId; - -// fn update_investment( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// amount: Self::Amount, -// ) -> Result<(), Self::Error> { -// let pre_amount = Self::investment(who, investment_id.clone())?; -// let pre_state = InvestmentState::::get(who, -// investment_id.clone()).unwrap_or_default(); - -// if amount > pre_amount { -// // TODO: Can payment currency be derived? -// let swap_currency = -// ::info(investment_id).map(|info| -// info.payment_currency()); let post_state: Option::Balance, ::CurrencyId>> = pre_state. -// transition(InvestTransition::IncreaseInvestOrder(amount))?; Ok(()) -// } else if amount < pre_amount { -// let post_state: Option::Balance, ::CurrencyId>> = pre_state. -// transition(InvestTransition::DecreaseInvestOrder(amount))?; Ok(()) -// } else { -// Ok(()) -// } -// } - -// fn accepted_payment_currency( -// investment_id: Self::InvestmentId, -// currency: Self::CurrencyId, -// ) -> bool { -// T::Investment::accepted_payment_currency(investment_id, currency) -// } - -// fn investment( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// ) -> Result { -// todo!() -// } - -// fn update_redemption( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// amount: Self::Amount, -// ) -> Result<(), Self::Error> { -// todo!() -// } - -// fn accepted_payout_currency( -// investment_id: Self::InvestmentId, -// currency: Self::CurrencyId, -// ) -> bool { -// T::Investment::accepted_payout_currency(investment_id, currency) -// } - -// fn redemption( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// ) -> Result { -// todo!() -// } -// } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs new file mode 100644 index 0000000000..8b879f6a53 --- /dev/null +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -0,0 +1,575 @@ +// 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 cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; +use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; +use frame_support::{traits::Get, transactional}; +use sp_runtime::{ + traits::{EnsureAdd, Zero}, + DispatchError, DispatchResult, +}; + +use crate::{ + types::{ + InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, Swap, + TokenSwapReason, + }, + Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, + RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, +}; + +mod invest; +mod redeem; + +// Handles the second stage of updating investments. Whichever (potentially +// async) code path of the first stage concludes it (partially) should call +// `Swap::Config::SwapNotificationHandler::notify_status_update(swap_order_id, +// swapped_amount)`. +impl StatusNotificationHook for Pallet { + type Error = DispatchError; + type Id = T::TokenSwapOrderId; + type Status = SwapOf; + + fn notify_status_change( + id: T::TokenSwapOrderId, + status: SwapOf, + ) -> Result<(), DispatchError> { + let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; + let reason = TokenSwapReasons::::get(id).ok_or(Error::::TokenSwapReasonNotFound)?; + + match reason { + TokenSwapReason::Investment => { + let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); + let post_state = pre_state + .transition(InvestTransition::FulfillSwapOrder(status)) + .map_err(|e| { + log::debug!( + "Encountered unexpected pre state {:?} when transitioning into {:?} \ + after (partially) fulfilling a swap", + pre_state, + status + ); + e + })?; + Pallet::::apply_state_transition(&info.owner, info.id, post_state.clone()).map( + |e| { + log::debug!( + "Encountered unexpected error when applying state transition to state \ + {:?}", + post_state + ); + e + }, + ) + } + TokenSwapReason::Redemption => { + let pre_state = RedemptionState::::get(&info.owner, info.id).unwrap_or_default(); + let post_state = pre_state + .transition(RedeemTransition::FulfillSwapOrder(status)) + .map_err(|e| { + log::debug!( + "Encountered unexpected pre state {:?} when transitioning into {:?} \ + after (partially) fulfilling a swap", + pre_state, + status + ); + e + })?; + todo!() + } + } + } +} + +impl ForeignInvestment for Pallet { + type Amount = T::Balance; + type CurrencyId = T::CurrencyId; + type Error = DispatchError; + type InvestmentId = T::InvestmentId; + + // Consumers such as Connectors should call this function instead of + // `Investment::update_invest_order` as this implementation accounts for + // (potentially) splitting the update into two stages. The second stage is + // resolved by `StatusNotificationHook::notify_status_change`. + fn update_foreign_invest_order( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + amount: T::Balance, + ) -> Result<(), DispatchError> { + let pre_amount = T::Investment::investment(who, investment_id.clone())?; + let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + + let post_state = if amount > pre_amount { + pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + // safe because amount > pre_amount + amount: amount - pre_amount, + })) + } else if amount < pre_amount { + pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { + currency_in: return_currency, + currency_out: pool_currency, + // safe because amount < pre_amount + amount: pre_amount - amount, + })) + } else { + Ok(pre_state) + }?; + + Pallet::::apply_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + fn update_foreign_redemption( + who: &T::AccountId, + // return_currency: T::CurrencyId, + // pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + amount: T::Balance, + ) -> Result<(), DispatchError> { + let pre_amount = T::Investment::redemption(who, investment_id.clone())?; + let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + + let post_state = if amount > pre_amount { + // safe because amount > pre_amount + pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount - pre_amount)) + } else if amount < pre_amount { + // safe because amount < pre_amount + pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount)) + } else { + Ok(pre_state) + }?; + + // Pallet::::apply_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + fn collect_foreign_investment( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + ) -> Result<(), DispatchError> { + todo!() + } + + fn collect_foreign_redemption( + who: &T::AccountId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + ) -> Result<(), DispatchError> { + todo!() + } +} + +impl Pallet { + /// Must be called after transitioning any `InvestState` via `transition` to + /// update the chain storage and execute various trait config hooks, e.g. + /// `ExecutedDecreaseHook`. + /// + /// NOTE: When updating token swap orders, only `handle_swap_order` should + /// be called! + #[transactional] + // TODO: Add/adjust apply_state_transition for redeem orders + fn apply_state_transition( + who: &T::AccountId, + investment_id: T::InvestmentId, + state: InvestState, + ) -> DispatchResult { + match state.clone() { + InvestState::NoState=> { + Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + + // Exit early to prevent setting InvestmentState + InvestmentState::::remove(who, investment_id); + return Ok(()); + }, + InvestState::InvestmentOngoing { invest_amount } => { + Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + }, + InvestState::ActiveSwapIntoPoolCurrency { swap } | + InvestState::ActiveSwapIntoReturnCurrency { swap } | + // We don't care about `done_amount` until swap into return is fulfilled + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { + Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + }, + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | + // We don't care about `done_amount` until swap into return is fulfilled + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { + Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + }, + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + + Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); + }, + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { + Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + + Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); + }, + InvestState::SwapIntoReturnDone { done_swap } => { + Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, Zero::zero())?; + + Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; + + // Exit early to prevent setting InvestmentState + InvestmentState::::remove(who, investment_id); + return Ok(()); + }, + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { + Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + T::Investment::update_investment(who, investment_id, invest_amount)?; + + Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; + + // Exit early to prevent setting InvestmentState + let new_state = InvestState::InvestmentOngoing { invest_amount }; + InvestmentState::::insert(who, investment_id, new_state); + return Ok(()); + }, + }; + + InvestmentState::::insert(who, investment_id, state); + // TODO: Emit event? + + Ok(()) + } + + /// Updates or kills a token swap order. If the final swap amount is zero, + /// kills the swap order and all associated storage. Else, creates or + /// updates an existing swap order. + /// + /// If the provided reason does not match the latest one stored in + /// `TokenSwapReasons`, also resolves the _merge conflict_ resulting from + /// updating and thus overwriting opposite swaps. See + /// [Self::handle_concurrent_swap_orders] for details. + /// + /// Returns potentially altered invest and redeem states which are not + /// updated in storage yet! + /// + /// NOTE: Should be the only swap order updating function which should be + /// called. + fn handle_swap_order( + who: &T::AccountId, + investment_id: T::InvestmentId, + maybe_swap: Option>, + reason: TokenSwapReason, + ) -> Result< + ( + Option>, + Option>, + ), + DispatchError, + > { + // check for concurrent conflicting swap orders + if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { + let (maybe_updated_swap, maybe_invest_state, maybe_redeem_state) = + Self::handle_concurrent_swap_orders(who, investment_id, swap_order_id, reason)?; + + // update or kill swap order with updated order having priority in case it was + // overwritten + if let Some(swap_order) = maybe_updated_swap { + Self::place_swap_order(who, investment_id, swap_order, reason)?; + } else if let Some(swap_order) = maybe_swap { + Self::place_swap_order(who, investment_id, swap_order, reason)?; + } else { + Self::kill_swap_order(who, investment_id)?; + } + + Ok((maybe_invest_state, maybe_redeem_state)) + } + // update to provided value, if not none + else if let Some(swap_order) = maybe_swap { + Self::place_swap_order(who, investment_id, swap_order, reason)?; + Ok((None, None)) + } else { + Ok((None, None)) + } + } + + /// Kills all storage associated with token swaps and cancels the + /// potentially active swap order. + /// + /// NOTE: Must only be called in `handle_swap_order`. + fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { + if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { + T::TokenSwaps::cancel_order(swap_order_id); + ForeignInvestmentInfo::::remove(swap_order_id); + TokenSwapReasons::::remove(swap_order_id); + } + Ok(()) + } + + /// Sets up `TokenSwapOrderIds` and `ForeignInvestmentInfo` storages, if the + /// order does not exist yet. Moreover, updates `TokenSwapReasons` pointer + /// to the provided value. + /// + /// NOTE: Must only be called in `handle_swap_order`. + fn place_swap_order( + who: &T::AccountId, + investment_id: T::InvestmentId, + swap: SwapOf, + reason: TokenSwapReason, + ) -> DispatchResult { + // exit early + if swap.amount.is_zero() { + return Self::kill_swap_order(who, investment_id); + } + if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { + T::TokenSwaps::update_order( + who.clone(), + swap_order_id, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + )?; + TokenSwapReasons::::insert(swap_order_id, reason); + + Ok(()) + } else { + // TODO: How to handle potential failure? + let swap_order_id = T::TokenSwaps::place_order( + who.clone(), + swap.currency_out, + swap.currency_in, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + )?; + TokenSwapOrderIds::::insert(who, investment_id, swap_order_id); + ForeignInvestmentInfo::::insert( + swap_order_id, + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ); + TokenSwapReasons::::insert(swap_order_id, reason); + + Ok(()) + } + } + + /// Determines the correct amount for a token swap based on the current + /// `InvestState` and `RedeemState` corresponding to the `TokenSwapOrderId`. + /// + /// Returns a tuple of the total swap order amount as well as potentially + /// altered invest and redeem states. Any returning tuple element which is + /// `None`, reflects that no change is required for this element. Else, it + /// needs to be applied to the storage. + /// + /// NOTE: Required since there exists at most one swap per `(AccountId, + /// InvestmentId)` pair whereas investments and redemptions can both mutate + /// orders. Assume, as a result of an `InvestState` transition, a token swap + /// order into pool currency is initialized. Then, as a result of a + /// `RedeemState` transition, a token swap order into return currency is + /// needed. This handler resolves the _merge conflict_ in situations where + /// the reason to create/update a swap order does not match the previous + /// reason. + /// + /// * Is noop, if the the current reason equals the previous one. + /// * If both states are swapping into return currency, i.e. their invest + /// and redeem states include `ActiveSwapIntoReturnCurrency`, the states + /// stay the same. However the total order amount needs to be updated by + /// summing up both swap order amounts. + /// * If the `InvestState` includes swapping into pool currency, i.e. + /// `ActiveSwapIntoPoolCurrency`, whereas the `RedeemState` is swapping + /// into the opposite direction, i.e. `ActiveSwapIntoReturnCurrency`, we + /// need to resolve the delta between both swap order amounts and update + /// the states accordingly. + fn handle_concurrent_swap_orders( + who: &T::AccountId, + investment_id: T::InvestmentId, + swap_order_id: T::TokenSwapOrderId, + reason: TokenSwapReason, + ) -> Result< + ( + Option>, + Option>, + Option>, + ), + DispatchError, + > { + let last_reason = + TokenSwapReasons::::get(swap_order_id).ok_or(Error::::TokenSwapReasonNotFound)?; + + // Exit early if both reasons match, i.e. we would not override any opposite + // swap order + if last_reason == reason { + return Ok((None, None, None)); + } + + // Read states from storage and determine amounts + let invest_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); + let redeem_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); + let invest_swap_amount = invest_state + .get_active_swap() + .map(|s| s.amount) + .unwrap_or_default(); + let redeem_swap_amount = redeem_state + .get_active_swap() + .map(|s| s.amount) + .unwrap_or_default(); + let resolved_amount = invest_swap_amount.min(redeem_swap_amount); + // safe because max >= min, equals zero if both amounts equal + let swap_amount_opposite_direction = + invest_swap_amount.max(redeem_swap_amount) - resolved_amount; + + // Determine new invest state + let new_invest_state = match invest_state.clone() { + // As redeem swap can only be into return currency, we need to delta on the opposite + // swap directions + InvestState::ActiveSwapIntoPoolCurrency { swap } => { + if invest_swap_amount > redeem_swap_amount { + Ok(Some( + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: swap_amount_opposite_direction, + ..swap + }, + invest_amount: resolved_amount, + }, + )) + } else { + Ok(Some(InvestState::InvestmentOngoing { + invest_amount: resolved_amount, + })) + } + } + // Same as above except for the base investment amount which is incremented + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: invest_swap, + invest_amount, + } => { + if invest_swap_amount > redeem_swap_amount { + Ok(Some( + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: swap_amount_opposite_direction, + ..invest_swap + }, + invest_amount: invest_amount.ensure_add(resolved_amount)?, + }, + )) + } else { + Ok(Some(InvestState::InvestmentOngoing { + invest_amount: invest_amount.ensure_add(resolved_amount)?, + })) + } + } + // We must not alter the invest state if there is no active pool currency swap + state => Ok(None), + } + .map_err(|e: DispatchError| e)?; + + // Determine final swap amount and new redeem state + let (final_swap_amount, new_redeem_state) = match invest_state.clone() { + // Opposite swaps cancel out at least one (or if equal amounts) both swaps + InvestState::ActiveSwapIntoPoolCurrency { .. } + | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } => { + let new_state = redeem_state + .fulfill_active_swap_amount( + redeem_swap_amount.min(swap_amount_opposite_direction), + ) + .unwrap_or(redeem_state); + + Ok((swap_amount_opposite_direction, new_state)) + } + // All leftover combinations either do not involve any active swaps or both + // swaps have the same direction, i.e. into return currency. Thus, we can + // leave states untouched and just add up the potential swap amount. + _ => Ok(( + invest_swap_amount.ensure_add(redeem_swap_amount)?, + redeem_state, + )), + } + .map(|(token_swap_amount, maybe_new_redeem_state)| { + // If old state match new state, no need to return it as this could cause a + // follow-up transition trigger + if redeem_state == maybe_new_redeem_state { + (token_swap_amount, None) + } else { + (token_swap_amount, Some(maybe_new_redeem_state)) + } + }) + .map_err(|e: DispatchError| e)?; + + // Determine token swap from amount + let token_swap = if invest_swap_amount > redeem_swap_amount { + invest_state.get_active_swap().map(|invest_swap| Swap { + amount: final_swap_amount, + ..invest_swap + }) + } + // handle redeem_swap_amount >= invest_swap_amount as well as all cases, in which neither + // states include an active swap + else { + redeem_state.get_active_swap().map(|redeem_swap| Swap { + amount: final_swap_amount, + ..redeem_swap + }) + }; + + Ok((token_swap, new_invest_state, new_redeem_state)) + } + + /// Sends `ExecutedDecreaseHook` notification such that any potential + /// consumer could act upon that, e.g. Connectors for + /// `ExecutedDecrease{Invest, Redeem}Order`. + fn send_executed_decrease_hook( + who: &T::AccountId, + investment_id: T::InvestmentId, + amount_payout: T::Balance, + ) -> DispatchResult { + // TODO(@mustermeiszer): Does this return the entire desired amount or do we + // need to tap into collecting? + let amount_remaining = T::Investment::investment(who, investment_id)?; + + // TODO(@mustermeiszer): Do we add the active swap amount? + T::ExecutedDecreaseHook::notify_status_change( + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ExecutedDecrease { + amount_payout, + amount_remaining, + }, + ) + } +} diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs new file mode 100644 index 0000000000..9581540829 --- /dev/null +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -0,0 +1,361 @@ +// 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 cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; +use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; +use frame_support::{traits::Get, transactional}; +use sp_runtime::{ + traits::{EnsureAdd, EnsureSub, Zero}, + ArithmeticError, DispatchError, DispatchResult, +}; + +use crate::{ + types::{InnerRedeemState, InvestTransition, RedeemState, RedeemTransition, Swap}, + Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, SwapOf, + TokenSwapOrderIds, +}; + +impl RedeemState +where + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +{ + /// Solely apply state machine to transition one `RedeemState` into another + /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#Redemption-States + /// + /// NOTE: MUST call `apply_state_transition` on the post state to actually + /// mutate storage. + pub fn transition( + &self, + transition: RedeemTransition, + ) -> Result { + match transition { + RedeemTransition::IncreaseRedeemOrder(amount) => Self::handle_increase(&self, amount), + RedeemTransition::DecreaseRedeemOrder(amount) => Self::handle_decrease(&self, amount), + RedeemTransition::FulfillSwapOrder(swap) => { + Self::handle_fulfilled_swap_order(&self, swap) + } + } + } + + /// Returns the potentially existing active swap into return currency in the + /// inner state: + /// * If the inner state includes `ActiveSwapIntoReturnCurrency`, it returns + /// the corresponding `Some(swap)`. + /// * Else, it returns `None`. + pub(crate) fn get_active_swap(&self) -> Option> { + match self { + Self::NoState => None, + Self::Invested { invest_amount } => None, + Self::NotInvestedAnd(inner) => inner.get_active_swap(), + Self::InvestedAnd(inner) => inner.get_active_swap(), + } + } + + pub(crate) fn swap_inner_state(&self, inner: InnerRedeemState) -> Self { + match self { + Self::InvestedAnd(_) => Self::InvestedAnd(inner), + Self::NotInvestedAnd(_) => Self::NotInvestedAnd(inner), + _ => *self, + } + } + + /// Reduce the amount of an active swap of the `InnerRedeemState` by the + /// provided value: + /// * Throws, if there is no active swap, i.e. the state does not include + /// `ActiveSwapIntoReturnCurrency`. + /// * Else If the provided value equals the swap amount, the state is + /// transitioned into `*AndSwapIntoReturnDone`. + /// * Else, it is transitioned int + /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + pub(crate) fn fulfill_active_swap_amount( + &self, + amount: Balance, + ) -> Result { + match self { + Self::InvestedAnd(inner) => { + Ok(Self::InvestedAnd(inner.fulfill_active_swap_amount(amount)?)) + } + Self::NotInvestedAnd(inner) => Ok(Self::NotInvestedAnd( + inner.fulfill_active_swap_amount(amount)?, + )), + _ => Err(DispatchError::Other( + "Cannot alter active swap amount for RedeemStates without swap", + )), + } + } + + // TODO: + // fn deconstruct_active_investment(&self) -> +} + +impl InnerRedeemState +where + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +{ + /// Returns the potentially existing active swap into return currency: + /// * If the inner state includes `ActiveSwapIntoReturnCurrency`, it returns + /// the corresponding `Some(swap)`. + /// * Else, it returns `None`. + fn get_active_swap(&self) -> Option> { + match *self { + Self::Redeeming { .. } => None, + Self::CollectableRedemption { .. } => None, + Self::RedeemingAndCollectableRedemption { .. } => None, + Self::ActiveSwapIntoReturnCurrency { swap } => Some(swap), + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + Self::SwapIntoReturnDone { .. } => None, + Self::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), + Self::RedeemingAndSwapIntoReturnDone { .. } => None, + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), + Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { .. } => None, + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), + Self::CollectableRedemptionAndSwapIntoReturnDone { .. } => None, + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + } + } + + /// Reduce the amount of an active swap by the provided value: + /// * Throws, if there is no active swap, i.e. the state does not include + /// `ActiveSwapIntoReturnCurrency`. + /// * Else If the provided value equals the swap amount, the state is + /// transitioned into `*AndSwapIntoReturnDone`. + /// * Else, it is transitioned int + /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + fn fulfill_active_swap_amount(&self, amount: Balance) -> Result { + match self { + Self::ActiveSwapIntoReturnCurrency { swap } => { + if amount == swap.amount{ + Ok(Self::SwapIntoReturnDone { done_swap: *swap }) + } else { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount: amount + } + ) + } + }, + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + + if amount == swap.amount { + Ok( + Self::SwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..*swap + } + } + ) + } else { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount, + } + ) + } + }, + Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + if amount == swap.amount { + Ok( + Self::RedeemingAndSwapIntoReturnDone { + done_swap: Swap { + amount, + ..*swap + }, + redeem_amount: *redeem_amount, + } + ) + } else { + Ok( + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount: amount, + redeem_amount: *redeem_amount, + } + ) + } + }, + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + + if amount == swap.amount { + Ok( + Self::RedeemingAndSwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..*swap + }, + redeem_amount: *redeem_amount, + } + ) + } else { + Ok( + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount, + redeem_amount: *redeem_amount, + } + ) + } + }, + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => { + if amount == swap.amount { + Ok( + Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + done_swap: *swap, + redeem_amount: *redeem_amount, + collect_amount: *collect_amount, + } + ) + } else { + Ok( + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount: amount, + redeem_amount: *redeem_amount, + collect_amount: *collect_amount, + } + ) + } + }, + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + + if amount == swap.amount { + Ok( + Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..*swap + }, + redeem_amount: *redeem_amount, + collect_amount: *collect_amount, + } + ) + } else { + Ok( + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount, + redeem_amount: *redeem_amount, + collect_amount: *collect_amount, + } + ) + } + }, + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + if amount == swap.amount { + Ok( + Self::CollectableRedemptionAndSwapIntoReturnDone { + done_swap: *swap, + collect_amount: *collect_amount, + } + ) + } else { + Ok( + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount: amount, + collect_amount: *collect_amount, + } + ) + } + }, + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + + if amount == swap.amount { + Ok( + Self::CollectableRedemptionAndSwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..*swap + }, + collect_amount: *collect_amount, + } + ) + } else { + Ok( + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount, + collect_amount: *collect_amount, + } + ) + } + }, + _ => Err(DispatchError::Other( + "Cannot increase done_amount of InnerRedeemState if it does not include active swap", + )) + } + } +} + +// Actual impl of transition +impl RedeemState +where + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +{ + fn handle_increase( + &self, + amount: Balance, + ) -> Result, DispatchError> { + todo!() + // match self {} + } + + fn handle_decrease( + &self, + amount: Balance, + ) -> Result, DispatchError> { + todo!() + } + + fn handle_fulfilled_swap_order( + &self, + swap: Swap, + ) -> Result, DispatchError> { + todo!() + } +} diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index bca365c71d..fd4845ca82 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -47,7 +47,7 @@ pub mod pallet { use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; - use types::InvestState; + use types::{InvestState, RedeemState, TokenSwapReason}; use super::*; @@ -194,11 +194,34 @@ pub mod pallet { InvestState, >; + /// Maps an investor and their `InvestmentId` to the corresponding + /// `RedeemState`. + /// + /// NOTE: The lifetime of this storage starts with increasing a redemption + /// if there exists a processed investment. It ends with transferring back + /// the swapped return currency to the corresponding source domain from + /// which the investment originated. The lifecycle must go through the + /// following stages: + /// 1. Increase redemption --> Initialize storage + /// 2. Fully process pending redemption + /// 3. Collect redemption + /// 4. Trigger swap from pool to return currency + /// 5. Completely fulfill swap order + /// 6. Transfer back to source domain --> Kill storage entry + #[pallet::storage] + pub(super) type RedemptionState = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, + RedeemState, + >; + + // TODO: How to deal with `RedeemState` here? /// Maps `TokenSwapOrders` to `InvestmentInfo` to implicitly enable mapping /// to `InvestmentState`. /// - /// NOTE: Here, the `payment_currency` refers to the `pool_currency`. - /// /// NOTE: The storage is immediately killed when the swap order is /// completely fulfilled even if the investment might not be fully /// processed. @@ -222,6 +245,23 @@ pub mod pallet { T::TokenSwapOrderId, >; + /// Maps a `TokenSwapOrderId` to the corresponding `TokenSwapReason` for + /// which it was last updated, i.e. `Investment` or `Redemption`. + /// + /// As there can always be at most a single active token swap for any + /// `TokenSwapOrderId`, and thus also for any `(AccountId, InvestmentId)` + /// pair, we only need to keep track of the last reason when we act upon a + /// notified status update for any ongoing swap. Otherwise, it would be + /// impossible to know whether an invest or a redeem transition needs to be + /// applied. + /// + /// NOTE: The storage is immediately killed when the swap order is + /// completely fulfilled even if the investment might not be fully + /// processed. + #[pallet::storage] + pub(super) type TokenSwapReasons = + StorageMap<_, Blake2_128Concat, T::TokenSwapOrderId, TokenSwapReason>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -235,6 +275,16 @@ pub mod pallet { /// /// NOTE: We must ensure, this can practically never happen! InvestmentInfoNotFound, + /// Failed to retrieve the `RedemptionInfo` from the given + /// `TokenSwapOrderId`. + /// + /// NOTE: We must ensure, this can practically never happen! + RedemptionInfoNotFound, + /// Failed to retrieve the `TokenSwapReason` from the given + /// `TokenSwapOrderId`. + /// + /// NOTE: We must ensure, this can practically never happen! + TokenSwapReasonNotFound, /// Failed to determine whether the corresponding currency can be either /// used for payment or payout of an investment. /// diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 835f6a39ac..3acffb8d27 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -35,6 +35,16 @@ pub struct Swap::Investment`. This includes swapping it /// into a pool currency or back, if the investment is decreased before it is @@ -135,6 +145,7 @@ pub enum InvestState< }, } +// TODO: Docs #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum InvestTransition< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, @@ -159,7 +170,18 @@ pub enum InvestTransition< /// This includes swapping it into a pool currency or back, if the investment is /// decreased before it is fully processed. #[derive( - Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, + Clone, + Copy, + Default, + PartialOrd, + Ord, + PartialEq, + Eq, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, )] pub enum RedeemState< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, @@ -182,7 +204,9 @@ pub enum RedeemState< /// Reflects all possible redeem states independent of whether an investment is /// still active or not in the actual `RedeemState`. -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[derive( + Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, +)] pub enum InnerRedeemState< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, Currency: Clone + Copy + PartialEq, @@ -302,6 +326,30 @@ pub enum InnerRedeemState< }, } +// TODO: +// #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, +// TypeInfo, MaxEncodedLen)] pub(crate) struct DeconstructedRedeemState where +// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, +// Currency: Clone + Copy + PartialEq, { +// pub(crate) swap: Swap, +// pub(crate) done_amount: Some(Balance), +// pub(crate) collectable_amount: Swap, +// pub(crate) redeem_amount: Swap, +// pub(crate) is_invested: bool, +// } + +// TODO: Docs +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub enum RedeemTransition< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, + Currency: Clone + Copy + PartialEq, +> { + IncreaseRedeemOrder(Balance), + DecreaseRedeemOrder(Balance), + FulfillSwapOrder(Swap), +} + // // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in // post // transition trigger and thus never exist as pre transition state // Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => { From 7c089130068fae41e81b7b51198ec28929891947 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 27 Jul 2023 11:20:54 +0200 Subject: [PATCH 11/96] fix: apply_invest_state_transition + docs improvements --- .../foreign-investments/src/impls/invest.rs | 73 ++++---- pallets/foreign-investments/src/impls/mod.rs | 158 ++++++++++++------ .../foreign-investments/src/impls/redeem.rs | 39 +++-- pallets/foreign-investments/src/types.rs | 24 +-- 4 files changed, 177 insertions(+), 117 deletions(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 80bd2f06e5..d4708eb278 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -26,8 +26,8 @@ where /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. /// - /// NOTE: MUST call `apply_state_transition` on the post state to actually - /// mutate storage. + /// NOTE: MUST call `apply_invest_state_transition` on the post state to + /// actually mutate storage. pub fn transition( &self, transition: InvestTransition, @@ -41,9 +41,8 @@ where } } - /// Returns the potentially existing active swap into either return or pool + /// Returns the potentially existing active swap into either pool or return /// currency: - /// /// * If the state includes `ActiveSwapInto{Pool, Return}Currency`, it /// returns `Some(swap)`. /// * Else, it returns `None`. @@ -77,8 +76,11 @@ where { // TODO: Add to spec /// Handle `increase` transitions depicted by `msg::increase` edges in the - /// state diagram. Behaves similar to a ledger when considering - /// `SwapIntoReturnDone` and `InvestmentOngoing` as the + /// state diagram: + /// * If there is no swap into return currency, the pool currency swap + /// amount is increased. + /// * Else, resolves opposite swap directions by immediately fulfilling the + /// side with lower amounts; or both if the swap amounts are equal. /// /// When we increase an investment, we normally have to swap it into pool /// currency (`ActiveSwapIntoPoolCurrency`) before it can be invested @@ -110,9 +112,9 @@ where /// `(done_amount = 1500, pool_swap.amount = 100, investing = 500)`. /// /// NOTE: We can ignore handling all states which include - /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// `*SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency*` as we /// consume the done amount and transition in the post transition phase. - /// To be safe and not make any unhandled assumptions, we throw + /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! fn handle_increase(&self, swap: Swap) -> Result { @@ -356,7 +358,12 @@ where } /// Handle `decrease` transitions depicted by `msg::decrease` edges in the - /// state diagram. + /// state diagram: + /// * If there is no swap into pool currency, the return currency swap + /// amount is increased up to the ongoing investment amount which is not + /// yet processed. + /// * Else, resolves opposite swap directions by immediately fulfilling the + /// side with lower amounts; or both if the swap amounts are equal. /// /// Throws if the decreasing amount exceeds the amount which is /// currently swapping into pool currency and/or investing as we cannot @@ -366,15 +373,12 @@ where /// NOTE: We can ignore handling all states which include /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. - /// To be safe and not make any unhandled assumptions, we throw - /// `DispatchError::Other` for these states though we need to make sure - /// this can never occur! - /// /// Moreover, we can ignore handling all states which do not include /// `ActiveSwapIntoPoolCurrency` or `InvestmentOngoing` as we cannot reduce - /// further then. To be safe and not make any unhandled assumptions, we - /// throw `DispatchError::Other` for these states though we need to - /// make sure this can never occur! + /// further then. + /// To be safe and to not make any unhandled assumptions, we throw + /// `DispatchError::Other` for these states though we need to make sure + /// this can never occur! fn handle_decrease(&self, swap: Swap) -> Result { // TODO(@review): Can we check this at an earlier stage? if swap.currency_in == swap.currency_out { @@ -553,14 +557,12 @@ where /// NOTE: We can ignore handling all states which include /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we /// consume the done amount and transition in the post transition phase. - /// To be safe and not make any unhandled assumptions, we throw + /// Moreover, we can ignore handling all states which do not include + /// `ActiveSwapInto{Pool, Return}Currency` as else there cannot be an active + /// token swap for investments. + /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! - /// - /// Moreover, we can ignore handling all states which do not include - /// `ActiveSwapInto{Pool, Return}Currency`. To be safe and not make any - /// unhandled assumptions, we throw `DispatchError::Other` for these - /// states though we need to make sure this can never occur! fn handle_fulfilled_swap_order( &self, swap: Swap, @@ -745,9 +747,15 @@ where /// Handle increase transitions for the same incoming and outgoing /// currencies. /// - /// NOTE: We can ignore any state which involves an active swap, i.e. + /// NOTE: We can ignore handling all states which include + /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// consume the done amount and transition in the post transition phase. + /// Moreover, we can ignore any state which involves an active swap, i.e. /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the /// in and out currency is the same. + /// To be safe and to not make any unhandled assumptions, we throw + /// `DispatchError::Other` for these states though we need to make sure + /// this can never occur! fn handle_increase_non_foreign( &self, swap: Swap, @@ -783,9 +791,15 @@ where /// Handle decrease transitions for the same incoming and outgoing /// currencies. /// - /// NOTE: We can ignore any state which involves an active swap, i.e. + /// NOTE: We can ignore handling all states which include + /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// consume the done amount and transition in the post transition phase. + /// Moreover, we can ignore any state which involves an active swap, i.e. /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the /// in and out currency is the same. + /// To be safe and to not make any unhandled assumptions, we throw + /// `DispatchError::Other` for these states though we need to make sure + /// this can never occur! fn handle_decrease_non_foreign( &self, swap: Swap, @@ -811,11 +825,12 @@ where // TODO(@review): Can we ensure this check at an earlier stage? - /// Ensures that the ingoing and outgoing currencies of two swaps - /// * Either match fully (in is in, out is out) if the swap direction is - /// the same for both swaps, i.e. (pool, pool) or (return, return) - /// * Or the ingoing and outgoing currencies match if the swap direction is - /// opposite, i.e. (pool, return) or (return, pool) + /// Ensures that the ingoing and outgoing currencies of two swaps... + /// * Either match fully (in1 = in2, out1 = out2) if the swap direction is + /// the same for both swaps, i.e. (pool, pool) or (return, return) + /// * Or the ingoing and outgoing currencies match (in1 = out2, out1 = in2) + /// if the swap direction is opposite, i.e. (pool, return) or (return, + /// pool) fn ensure_currencies_match( is_same_swap_direction: bool, swap_1: &Swap, diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 8b879f6a53..c23eb545c2 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -61,16 +61,15 @@ impl StatusNotificationHook for Pallet { ); e })?; - Pallet::::apply_state_transition(&info.owner, info.id, post_state.clone()).map( - |e| { + Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state.clone()) + .map(|e| { log::debug!( "Encountered unexpected error when applying state transition to state \ {:?}", post_state ); e - }, - ) + }) } TokenSwapReason::Redemption => { let pre_state = RedemptionState::::get(&info.owner, info.id).unwrap_or_default(); @@ -129,7 +128,7 @@ impl ForeignInvestment for Pallet { Ok(pre_state) }?; - Pallet::::apply_state_transition(who, investment_id, post_state)?; + Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) } @@ -154,7 +153,7 @@ impl ForeignInvestment for Pallet { Ok(pre_state) }?; - // Pallet::::apply_state_transition(who, investment_id, post_state)?; + // Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(()) } @@ -179,93 +178,154 @@ impl ForeignInvestment for Pallet { } impl Pallet { - /// Must be called after transitioning any `InvestState` via `transition` to - /// update the chain storage and execute various trait config hooks, e.g. - /// `ExecutedDecreaseHook`. + // fn pre_state_transition_invest( + // who: &T::AccountId, + // investment_id: T::InvestmentId, + // state: InvestState, + // ) -> DispatchResult { + + /// Applies in-memory transitions of `InvestState` to chain storage. Always + /// updates/removes `InvestmentState` and the current investment. Depending + /// on the state, also kills/updates the current token swap order as well as + /// notifies `ExecutedDecreasedHook`. /// - /// NOTE: When updating token swap orders, only `handle_swap_order` should - /// be called! + /// The following execution order must not be changed: + /// + /// 1. If the `InvestState` includes `SwapIntoReturnDone` without + /// `ActiveSwapIntoReturnCurrency`: Send executed decrease hook & transition + /// state into its form without `SwapIntoReturnDone`. If the state is just + /// `SwapIntoReturnDone`, kill it. + /// + /// 2. Update the `InvestmentState` storage. This step is required as the + /// next step reads this storage entry. + /// + /// 3. Handle the token swap order by either creating, updating or killing + /// it. Depending on the current swap order and the previous and current + /// reason to update it, both the current `InvestmentState` as well as + /// `RedemptionState` might require an update. + /// + /// 4. If the token swap handling resulted in a new `InvestState`, update + /// `InvestmentState` again. + /// + /// 5. If the token swap handling resulted in a new `RedemptionState`, + /// update `RedemptionState`. + /// + /// 6. Update the investment. This also includes setting it to zero. We + /// assume the impl of `T::Investment` handles this case. + /// + /// NOTES: + /// * Must be called after transitioning any `InvestState` via + /// `transition` to update the chain storage. + /// * When updating token swap orders, only `handle_swap_order` should + /// be called #[transactional] - // TODO: Add/adjust apply_state_transition for redeem orders - fn apply_state_transition( + // TODO: Add/adjust apply_invest_state_transition for redeem orders + fn apply_invest_state_transition( who: &T::AccountId, investment_id: T::InvestmentId, state: InvestState, ) -> DispatchResult { - match state.clone() { - InvestState::NoState=> { - Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - - // Exit early to prevent setting InvestmentState + let invest_amount = match state.clone() { + InvestState::NoState => { InvestmentState::::remove(who, investment_id); - return Ok(()); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) }, InvestState::InvestmentOngoing { invest_amount } => { - Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; + InvestmentState::::insert(who, investment_id, state); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) }, InvestState::ActiveSwapIntoPoolCurrency { swap } | InvestState::ActiveSwapIntoReturnCurrency { swap } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { - Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; + InvestmentState::::insert(who, investment_id, state); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { - Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; + InvestmentState::::insert(who, investment_id, state); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - // Exit early to prevent setting InvestmentState let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order( + who, + investment_id, + Some(swap.clone()), + TokenSwapReason::Investment, + )?; + + Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; - // Exit early to prevent setting InvestmentState let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) }, InvestState::SwapIntoReturnDone { done_swap } => { - Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, Zero::zero())?; - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; - // Exit early to prevent setting InvestmentState InvestmentState::::remove(who, investment_id); - return Ok(()); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) }, InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { - Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - T::Investment::update_investment(who, investment_id, invest_amount)?; - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; - // Exit early to prevent setting InvestmentState let new_state = InvestState::InvestmentOngoing { invest_amount }; InvestmentState::::insert(who, investment_id, new_state); - return Ok(()); + + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; + + Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) }, - }; + } + // update invest and redeem states if necessary + .map(|(maybe_invest_state, invest_amount, maybe_redeem_state)| { + InvestmentState::::mutate(who, investment_id, |current_invest_state| { + if maybe_invest_state != *current_invest_state { + *current_invest_state = maybe_invest_state; + } + // TODO: Maybe emit event of invest state transition from `state` to `current_invest_state` + }); + + RedemptionState::::mutate(who, investment_id, |current_redeem_state| { + if maybe_redeem_state != *current_redeem_state { + *current_redeem_state = maybe_redeem_state; + // TODO: Maybe emit event of redeem state transition from `current_redeem_state` to `new_state` + } + }); + + invest_amount + }).map_err(|e: DispatchError| e)?; - InvestmentState::::insert(who, investment_id, state); - // TODO: Emit event? + // Finally, update investment after all states have been updated + T::Investment::update_investment(who, investment_id, invest_amount)?; Ok(()) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 9581540829..76360d9911 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -33,8 +33,8 @@ where /// Solely apply state machine to transition one `RedeemState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#Redemption-States /// - /// NOTE: MUST call `apply_state_transition` on the post state to actually - /// mutate storage. + /// NOTE: MUST call `apply_redeem_state_transition` on the post state to + /// actually mutate storage. pub fn transition( &self, transition: RedeemTransition, @@ -48,7 +48,7 @@ where } } - /// Returns the potentially existing active swap into return currency in the + /// Returns the potentially existing active swap into return currency of the /// inner state: /// * If the inner state includes `ActiveSwapIntoReturnCurrency`, it returns /// the corresponding `Some(swap)`. @@ -62,6 +62,7 @@ where } } + // TODO: Mayb remove or add docs pub(crate) fn swap_inner_state(&self, inner: InnerRedeemState) -> Self { match self { Self::InvestedAnd(_) => Self::InvestedAnd(inner), @@ -70,14 +71,19 @@ where } } - /// Reduce the amount of an active swap of the `InnerRedeemState` by the - /// provided value: - /// * Throws, if there is no active swap, i.e. the state does not include - /// `ActiveSwapIntoReturnCurrency`. - /// * Else If the provided value equals the swap amount, the state is + /// Reduce the amount of an active swap (into return currency) of the + /// `InnerRedeemState` by the provided value: + /// * If the provided value equals the swap amount, the state is /// transitioned into `*AndSwapIntoReturnDone`. - /// * Else, it is transitioned int + /// * Else, it is transitioned into /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + /// + /// NOTE: Throws if any of the following holds true: + /// * The outer `RedeemState` is not `InvestedAnd` or `NotInvested` as this + /// implies there is no active swap. + /// * The inner state is not an active swap, i.e. the state does not include + /// `ActiveSwapIntoReturnCurrency`. + /// * The reducible amount exceeds the active swap amount. pub(crate) fn fulfill_active_swap_amount( &self, amount: Balance, @@ -94,9 +100,6 @@ where )), } } - - // TODO: - // fn deconstruct_active_investment(&self) -> } impl InnerRedeemState @@ -128,12 +131,14 @@ where } } - /// Reduce the amount of an active swap by the provided value: - /// * Throws, if there is no active swap, i.e. the state does not include - /// `ActiveSwapIntoReturnCurrency`. - /// * Else If the provided value equals the swap amount, the state is + /// Reduce the amount of an active swap (into return currency) by the + /// provided value: + /// * Throws if there is no active swap, i.e. the state does not include + /// `ActiveSwapIntoReturnCurrency` or if the reducible amount exceeds the + /// swap amount + /// * If the provided value equals the swap amount, the state is /// transitioned into `*AndSwapIntoReturnDone`. - /// * Else, it is transitioned int + /// * Else, it is transitioned into /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. fn fulfill_active_swap_amount(&self, amount: Balance) -> Result { match self { diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 3acffb8d27..5ca607ae36 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -237,8 +237,8 @@ pub enum InnerRedeemState< /// return currency. /// /// NOTE: This state does not require handling in `RedeemState::transition` - /// as it must be manually transitioned in `apply_state_transition`, similar - /// to the corresponding state in `InvestState`. + /// as it must be manually transitioned in `apply_redeem_state_transition`, + /// similar to the corresponding state in `InvestState`. SwapIntoReturnDone { done_swap: Swap }, /// The redemption is split into two parts: /// * One part is waiting to be processed as redemption. @@ -349,23 +349,3 @@ pub enum RedeemTransition< DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), } - -// // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in -// post // transition trigger and thus never exist as pre transition state -// Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { .. } => { -// Err(DispatchError::Other("Invalid pre state, should automatically be -// transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")) } -// // Should be updated to `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in -// post // transition trigger and thus never exist as pre transition state -// Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { -// .. -// } => Err(DispatchError::Other("Invalid pre state, should automatically be -// transitioned into ActiveSwapIntoPoolCurrencyAndInvestmentOngoing")), // -// Should be cleared entirely in post transition trigger and thus never exist as -// pre // transition state Self::SwapIntoReturnDone { .. } => -// Err(DispatchError::Other("Invalid pre state, should automatically be -// transitioned into NoState")), // Should be updated to `InvestmentOngoing` in -// post transition trigger and thus never // exist as pre transition state -// Self::SwapIntoReturnDoneAndInvestmentOngoing { .. } => -// Err(DispatchError::Other("Invalid pre state, should automatically be -// transitioned into InvestmentOngoing")), From fb16e0ea850d8f608ce857d1a6404e9899efdbbd Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 28 Jul 2023 21:00:21 +0200 Subject: [PATCH 12/96] feat: redeem transitions (but collecting) --- libs/traits/src/lib.rs | 44 +- .../foreign-investments/src/delete_impls.rs | 70 ---- .../foreign-investments/src/impls/invest.rs | 21 +- pallets/foreign-investments/src/impls/mod.rs | 2 +- .../foreign-investments/src/impls/redeem.rs | 389 ++++++++++++++++-- pallets/foreign-investments/src/lib.rs | 3 +- pallets/foreign-investments/src/types.rs | 30 +- 7 files changed, 416 insertions(+), 143 deletions(-) delete mode 100644 pallets/foreign-investments/src/delete_impls.rs diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 1aec99e3be..b78c7b9e44 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -735,9 +735,20 @@ pub trait ForeignInvestment { type Error: Debug; type InvestmentId; - // TODO: Docs - /// * Apply state transition - /// * Kick off swap + /// Initiates the update of a foreign investment amount in `return_currency` + /// of who into the investment class `pool_currency` to amount. + /// + /// In general, we can assume that return and pool currency mismatch and + /// that swapping one into the other happens asynchronously. In that case, + /// the finalization of updating the investment needs to be handled + /// decoupled from the ForeignInvestment trait. + /// + /// NOTE: In practice, Consumers such as Connectors should call + /// this function instead of `Investment::update_investment` as this + /// implementation accounts for (potentially) splitting the update into two + /// stages. The second stage is resolved by + /// acting upon `StatusNotificationHook::notify_status_change` which is sent + /// by `TokenSwaps` trait implementor. fn update_foreign_invest_order( who: &AccountId, return_currency: Self::CurrencyId, @@ -746,7 +757,20 @@ pub trait ForeignInvestment { amount: Self::Amount, ) -> Result<(), Self::Error>; - // TODO: Docs + /// Initiates the update of a foreign redemption amount from `pool_currency` + /// of who into `return_currency` to amount. + /// + /// In general, we can assume that return and pool currency mismatch and + /// that swapping one into the other happens asynchronously. In that case, + /// the finalization of updating the redemption needs to be handled + /// decoupled from the ForeignInvestment trait. + /// + /// NOTE: In practice, Consumers such as Connectors should call + /// this function instead of `Investment::update_redemption` as this + /// implementation accounts for (potentially) splitting the update into two + /// stages. The second stage is resolved by + /// acting upon `StatusNotificationHook::notify_status_change` which is sent + /// by `TokenSwaps` trait implementor. fn update_foreign_redemption( who: &AccountId, // TODO: Check if we do not require them if can be derived in CollectRedeemOrder @@ -754,9 +778,7 @@ pub trait ForeignInvestment { // pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, amount: Self::Amount, - ) -> Result<(), Self::Error> { - todo!() - } + ) -> Result<(), Self::Error>; // TODO: Docs fn collect_foreign_investment( @@ -764,9 +786,7 @@ pub trait ForeignInvestment { return_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, - ) -> Result<(), Self::Error> { - todo!() - } + ) -> Result<(), Self::Error>; // TODO: Docs fn collect_foreign_redemption( @@ -774,9 +794,7 @@ pub trait ForeignInvestment { return_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, - ) -> Result<(), Self::Error> { - todo!() - } + ) -> Result<(), Self::Error>; } pub trait StatusNotificationHook { diff --git a/pallets/foreign-investments/src/delete_impls.rs b/pallets/foreign-investments/src/delete_impls.rs deleted file mode 100644 index df5c2536f4..0000000000 --- a/pallets/foreign-investments/src/delete_impls.rs +++ /dev/null @@ -1,70 +0,0 @@ -// TODO: How to merge token swaps and investment trait? Create new trait -// ForeignInvestment? > Check diagrams - -// impl Investment for Pallet { -// type Amount = T::Balance; -// type CurrencyId = T::CurrencyId; -// type Error = DispatchError; -// type InvestmentId = T::InvestmentId; - -// fn update_investment( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// amount: Self::Amount, -// ) -> Result<(), Self::Error> { -// let pre_amount = Self::investment(who, investment_id.clone())?; -// let pre_state = InvestmentState::::get(who, -// investment_id.clone()).unwrap_or_default(); - -// if amount > pre_amount { -// // TODO: Can payment currency be derived? -// let swap_currency = -// ::info(investment_id).map(|info| -// info.payment_currency()); let post_state: Option::Balance, ::CurrencyId>> = pre_state. -// transition(InvestTransition::IncreaseInvestOrder(amount))?; Ok(()) -// } else if amount < pre_amount { -// let post_state: Option::Balance, ::CurrencyId>> = pre_state. -// transition(InvestTransition::DecreaseInvestOrder(amount))?; Ok(()) -// } else { -// Ok(()) -// } -// } - -// fn accepted_payment_currency( -// investment_id: Self::InvestmentId, -// currency: Self::CurrencyId, -// ) -> bool { -// T::Investment::accepted_payment_currency(investment_id, currency) -// } - -// fn investment( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// ) -> Result { -// todo!() -// } - -// fn update_redemption( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// amount: Self::Amount, -// ) -> Result<(), Self::Error> { -// todo!() -// } - -// fn accepted_payout_currency( -// investment_id: Self::InvestmentId, -// currency: Self::CurrencyId, -// ) -> bool { -// T::Investment::accepted_payout_currency(investment_id, currency) -// } - -// fn redemption( -// who: &T::AccountId, -// investment_id: Self::InvestmentId, -// ) -> Result { -// todo!() -// } -// } diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index d4708eb278..e131d4040b 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -74,9 +74,8 @@ where Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, Currency: Clone + Copy + PartialEq, { - // TODO: Add to spec /// Handle `increase` transitions depicted by `msg::increase` edges in the - /// state diagram: + /// invest state diagram: /// * If there is no swap into return currency, the pool currency swap /// amount is increased. /// * Else, resolves opposite swap directions by immediately fulfilling the @@ -94,7 +93,7 @@ where /// of immediately fulfilling the pool swap order up to the possible amount. /// /// Example: - /// * Say before my pre state has `return_done = 1000` and + /// * Say before my pre invest state has `return_done = 1000` and /// `return_swap.amount = 500`. Now we look at three scenarios in which we /// increase below, exactly at and above the `return_swap.amount`: /// * a) If we increase by 500, we can reduce the `return_swap.amount` @@ -351,7 +350,7 @@ where } } _ => Err(DispatchError::Other( - "Invalid pre state, should automatically be transitioned into \ + "Invalid invest state, should automatically be transitioned into \ ActiveSwapIntoPoolCurrencyAndInvestmentOngoing", )), } @@ -390,7 +389,7 @@ where InvestState::NoState | InvestState::ActiveSwapIntoReturnCurrency { .. } | InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => { - Err(DispatchError::Other("Invalid pre state when transitioning a decrease")) + Err(DispatchError::Other("Invalid invest state when transitioning a decrease")) }, // Increment return swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { @@ -535,7 +534,7 @@ where } }, _ => Err(DispatchError::Other( - "Invalid pre state, should automatically be transitioned into \ + "Invalid invest state, should automatically be transitioned into \ ActiveSwapIntoPoolCurrencyAndInvestmentOngoing", )), } @@ -569,7 +568,7 @@ where ) -> Result { match &self { InvestState::NoState | InvestState::InvestmentOngoing { .. } => Err(DispatchError::Other( - "Invalid pre state when transitioning a fulfilled order", + "Invalid invest state when transitioning a fulfilled order", )), // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { @@ -736,7 +735,7 @@ where } }, _ => Err(DispatchError::Other( - "Invalid pre state, should automatically be transitioned into state without AndSwapIntoReturnDone", + "Invalid invest state, should automatically be transitioned into state without AndSwapIntoReturnDone", )), } } @@ -775,11 +774,11 @@ where | Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { .. } => Err(DispatchError::Other( - "Invalid pre state when transitioning an increased swap order with the same in- \ + "Invalid invest state when transitioning an increased swap order with the same in- \ and outgoing currency", )), _ => Err(DispatchError::Other( - "Invalid pre state, should automatically be transitioned into state without \ + "Invalid invest state, should automatically be transitioned into state without \ AndSwapIntoReturnDone", )), } @@ -817,7 +816,7 @@ where // should never occur but let's be safe here else { Err(DispatchError::Other( - "Invalid pre state when transitioning a decreased swap order with the same in- \ + "Invalid invest state when transitioning a decreased swap order with the same in- \ and outgoing currency", )) } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index c23eb545c2..40ce1c0b24 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -84,7 +84,7 @@ impl StatusNotificationHook for Pallet { ); e })?; - todo!() + todo!("apply_redeem_state_transition") } } } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 76360d9911..11ee354c1d 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -13,14 +13,30 @@ use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; -use frame_support::{traits::Get, transactional}; +use frame_support::{ensure, traits::Get, transactional}; use sp_runtime::{ traits::{EnsureAdd, EnsureSub, Zero}, ArithmeticError, DispatchError, DispatchResult, }; use crate::{ - types::{InnerRedeemState, InvestTransition, RedeemState, RedeemTransition, Swap}, + types::{ + InnerRedeemState, + InnerRedeemState::{ + ActiveSwapIntoReturnCurrency, ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + CollectableRedemption, CollectableRedemptionAndActiveSwapIntoReturnCurrency, + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + CollectableRedemptionAndSwapIntoReturnDone, Redeeming, + RedeemingAndActiveSwapIntoReturnCurrency, + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + RedeemingAndCollectableRedemption, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone, RedeemingAndSwapIntoReturnDone, + SwapIntoReturnDone, + }, + InvestTransition, RedeemState, RedeemTransition, Swap, + }, Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, SwapOf, TokenSwapOrderIds, }; @@ -57,16 +73,36 @@ where match self { Self::NoState => None, Self::Invested { invest_amount } => None, - Self::NotInvestedAnd(inner) => inner.get_active_swap(), - Self::InvestedAnd(inner) => inner.get_active_swap(), + Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { + inner.get_active_swap() + } } } - // TODO: Mayb remove or add docs - pub(crate) fn swap_inner_state(&self, inner: InnerRedeemState) -> Self { + /// Returns the potentially existing redeeming amount of the inner state: + /// * If the inner state includes `Redeeming`, it returns the corresponding + /// `Some(amount)`. + /// * Else, it returns `None`. + pub(crate) fn get_redeeming_amount(&self) -> Option { match self { - Self::InvestedAnd(_) => Self::InvestedAnd(inner), - Self::NotInvestedAnd(_) => Self::NotInvestedAnd(inner), + Self::NoState => None, + Self::Invested { invest_amount } => None, + Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { + inner.get_redeeming_amount() + } + } + } + + /// Exchanges the inner state of `RedeemState::InvestedAnd` as well as + /// `RedeemState::NotInvestedAnd` with the provided one similar to a memory + /// swap. + pub(crate) fn swap_inner_state(&self, inner: InnerRedeemState) -> Self { + match *self { + Self::InvestedAnd { invest_amount, .. } => Self::InvestedAnd { + invest_amount, + inner, + }, + Self::NotInvestedAnd { .. } => Self::NotInvestedAnd { inner }, _ => *self, } } @@ -89,17 +125,22 @@ where amount: Balance, ) -> Result { match self { - Self::InvestedAnd(inner) => { - Ok(Self::InvestedAnd(inner.fulfill_active_swap_amount(amount)?)) - } - Self::NotInvestedAnd(inner) => Ok(Self::NotInvestedAnd( - inner.fulfill_active_swap_amount(amount)?, - )), + Self::InvestedAnd { inner, .. } | Self::NotInvestedAnd { inner } => Ok( + Self::swap_inner_state(&self, inner.fulfill_active_swap_amount(amount)?), + ), _ => Err(DispatchError::Other( "Cannot alter active swap amount for RedeemStates without swap", )), } } + + // pub(crate) increase_invested(&self, amount: Balance) -> Result { match self { + // Self::InvestedAnd { invest_amount, inner } => { + + // } + // } + // } } impl InnerRedeemState @@ -108,8 +149,8 @@ where Currency: Clone + Copy + PartialEq, { /// Returns the potentially existing active swap into return currency: - /// * If the inner state includes `ActiveSwapIntoReturnCurrency`, it returns - /// the corresponding `Some(swap)`. + /// * If the state includes `ActiveSwapIntoReturnCurrency`, it returns the + /// corresponding `Some(swap)`. /// * Else, it returns `None`. fn get_active_swap(&self) -> Option> { match *self { @@ -131,6 +172,30 @@ where } } + /// Returns the potentially existing redeeming amount: + /// * If the state includes `Redeeming`, it returns the corresponding + /// `Some(amount)`. + /// * Else, it returns `None`. + fn get_redeeming_amount(&self) -> Option { + match *self { + Self::Redeeming { redeem_amount } => Some(redeem_amount), + Self::CollectableRedemption { .. } => None, + Self::RedeemingAndCollectableRedemption { redeem_amount, .. } => Some(redeem_amount), + Self::ActiveSwapIntoReturnCurrency { .. } => None, + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => None, + Self::SwapIntoReturnDone { .. } => None, + Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, .. } => Some(redeem_amount), + Self::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, .. } => Some(redeem_amount), + Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } => None, + Self::CollectableRedemptionAndSwapIntoReturnDone { .. } => None, + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => None, + } + } + /// Reduce the amount of an active swap (into return currency) by the /// provided value: /// * Throws if there is no active swap, i.e. the state does not include @@ -330,10 +395,162 @@ where } }, _ => Err(DispatchError::Other( - "Cannot increase done_amount of InnerRedeemState if it does not include active swap", + "Invalid inner redeem state when fulfilling active swap amount", )) } } + + /// Sets the redeeming amount to the provided value: + /// * If the value is not zero and the state involves `Redeeming`: Sets the + /// amount. + /// * Else if the value is not zero and the state does not involve + /// `Redeeming`: Adds `Redeeming` to the state with the corresponding + /// amount. + /// * If the value is zero and the state includes `Redeeming`: Removes + /// `Redeeming` from the state. + /// * Else throws. + /// + /// NOTE: If setting the amount to a non-zero value, assumes this function + /// is **only called on inner states of `RedeemState::InvestedAnd`** as the + /// redeeming amounts can at most equal the processed investment amount. + /// Since the inner state has no knowledge about the investment amount, this + /// check must be done beforehand. + fn set_redeem_amount(&self, amount: Balance) -> Result { + // Remove `Redeeming` from state + if amount.is_zero() { + match *self { + Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), + RedeemingAndCollectableRedemption { collect_amount, .. } => Ok(CollectableRedemption { collect_amount }), + RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(ActiveSwapIntoReturnCurrency { swap }), + RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(SwapIntoReturnDone { done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount }), + // Throw for states without `Redeeming` + inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), + } + } + // Set `redeeming` to non-zero value. Add `Redeeming` if not part of state yet. + else { + match *self { + Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), + RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount, collect_amount }), + RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, collect_amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, collect_amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, collect_amount, swap, done_amount }), + CollectableRedemption { collect_amount } => Ok(RedeemingAndCollectableRedemption { collect_amount, redeem_amount: amount }), + ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), + SwapIntoReturnDone { done_swap } => Ok(RedeemingAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap, redeem_amount: amount }), + CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount, redeem_amount: amount }), + } + } + } + + /// Transition all inner states which include + /// `ActiveSwapIntoReturnCurrency` either into `*SwapIntoReturnDone` or + /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + /// + /// Throws if the fulfilled swap direction is not into return currency or if + /// the amount exceeds the states active swap amount. + /// + /// NOTE: We can ignore all states which do not include + /// `ActiveSwapIntoReturnCurrency`. + fn transition_fulfilled_swap_order( + &self, + fulfilled_swap: Swap, + ) -> Result { + ensure!( + self.get_active_swap() + .map(|swap| { + swap.amount >= fulfilled_swap.amount + && swap.currency_in == fulfilled_swap.currency_in + && swap.currency_out == fulfilled_swap.currency_out + }) + .unwrap_or(true), + DispatchError::Other( + "Invalid inner redeem state when transitioning fulfilled swap order" + ) + ); + + let Swap { amount, .. } = fulfilled_swap; + + match *self { + Redeeming { .. } | + CollectableRedemption { .. } | + RedeemingAndCollectableRedemption { .. } | + SwapIntoReturnDone { .. } | + RedeemingAndSwapIntoReturnDone { .. } | + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { .. } | + CollectableRedemptionAndSwapIntoReturnDone { .. } => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), + ActiveSwapIntoReturnCurrency { swap } => { + if amount < swap.amount { + Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) + } else { + Ok(SwapIntoReturnDone { done_swap: swap }) + } + }, + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + if amount < swap.amount { + Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) + } else { + Ok(SwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) + } + }, + RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + if amount < swap.amount { + Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) + } else { + Ok(RedeemingAndSwapIntoReturnDone { done_swap: swap, redeem_amount }) + } + }, + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + if amount < swap.amount { + Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) + } else { + Ok(RedeemingAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) + } + }, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => { + if amount < swap.amount { + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount, collect_amount }) + } else { + Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, redeem_amount, collect_amount }) + } + }, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + if amount < swap.amount { + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount, collect_amount }) + } else { + Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount, collect_amount }) + } + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + if amount < swap.amount { + Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, collect_amount }) + } else { + Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, collect_amount }) + } + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + let done_amount = done_amount.ensure_add(amount)?; + if amount < swap.amount { + Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, collect_amount }) + } else { + Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, collect_amount }) + } + }, + } + } } // Actual impl of transition @@ -342,25 +559,137 @@ where Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, Currency: Clone + Copy + PartialEq, { - fn handle_increase( - &self, - amount: Balance, - ) -> Result, DispatchError> { - todo!() - // match self {} + /// Handle `increase` transitions depicted by `msg::increase` edges in the + /// redeem state diagram: + /// * If the current state includes a processed investment, i.e. is either + /// `RedeemState::Invested` or `RedeemState::InvestedAnd(..)`, decreases + /// the invest amount and increases the redeeming amount. Throws if the + /// investment amount is exceeded as this reflects the max redeeming + /// amount. + /// * Else throws for incorrect pre state. + fn handle_increase(&self, amount: Balance) -> Result { + match self { + Self::NoState | Self::NotInvestedAnd { .. } => Err(DispatchError::Other( + "Invalid redeem state when transitioning an increase", + )), + Self::Invested { invest_amount } => { + if &amount == invest_amount { + Ok(Self::NotInvestedAnd { + inner: Redeeming { + redeem_amount: amount, + }, + }) + } else { + Ok(Self::InvestedAnd { + invest_amount: invest_amount.ensure_sub(amount)?, + inner: Redeeming { + redeem_amount: amount, + }, + }) + } + } + Self::InvestedAnd { + invest_amount, + inner, + } => { + if &amount == invest_amount { + Ok(Self::NotInvestedAnd { + inner: inner.set_redeem_amount(amount)?, + }) + } else { + Ok(Self::InvestedAnd { + invest_amount: invest_amount.ensure_sub(amount)?, + inner: inner.set_redeem_amount(amount)?, + }) + } + } + } } - fn handle_decrease( - &self, - amount: Balance, - ) -> Result, DispatchError> { - todo!() + fn handle_decrease(&self, amount: Balance) -> Result { + let error_not_redeeming = Err(DispatchError::Other( + "Invalid redeem state when transitioning a decrease", + )); + + match self.get_redeeming_amount() { + None => error_not_redeeming, + // Can only decrease up to current redeeming amount + Some(redeem_amount) if redeem_amount <= amount => { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } + // Entire redeeming amount becomes invested amount, i.e. remove `Redeeming` from inner + // state + Some(redeem_amount) if redeem_amount == amount => match self { + Self::NoState | Self::Invested { .. } => error_not_redeeming, + Self::Invested { invest_amount } => error_not_redeeming, + Self::NotInvestedAnd { inner } => match inner { + Redeeming { .. } => Ok(Self::Invested { + invest_amount: amount, + }), + _ => Ok(Self::InvestedAnd { + invest_amount: amount, + inner: inner.set_redeem_amount(Balance::zero())?, + }), + }, + Self::InvestedAnd { + invest_amount, + inner, + } => { + let invest_amount = invest_amount.ensure_add(amount)?; + match inner { + Redeeming { .. } => Ok(Self::Invested { invest_amount }), + _ => Ok(Self::InvestedAnd { + invest_amount, + inner: inner.set_redeem_amount(Balance::zero())?, + }), + } + } + }, + // Partial redeeming amount becomes invested amount, i.e. keep `Redeeming` in inner + // state + Some(old_redeem_amount) => { + let redeem_amount = old_redeem_amount.ensure_sub(amount)?; + + match self { + Self::NoState | Self::Invested { .. } => error_not_redeeming, + Self::Invested { invest_amount } => error_not_redeeming, + Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { + invest_amount: amount, + inner: inner.set_redeem_amount(redeem_amount)?, + }), + Self::InvestedAnd { + invest_amount, + inner, + } => { + let invest_amount = invest_amount.ensure_add(amount)?; + Ok(Self::InvestedAnd { + invest_amount, + inner: inner.set_redeem_amount(redeem_amount)?, + }) + } + } + } + } } fn handle_fulfilled_swap_order( &self, swap: Swap, - ) -> Result, DispatchError> { - todo!() + ) -> Result { + match self { + Self::NoState | Self::Invested { .. } => Err(DispatchError::Other( + "Invalid invest state when transitioning a fulfilled order", + )), + Self::NotInvestedAnd { inner } => Ok(Self::NotInvestedAnd { + inner: inner.transition_fulfilled_swap_order(swap)?, + }), + Self::InvestedAnd { + invest_amount, + inner, + } => Ok(Self::InvestedAnd { + invest_amount: *invest_amount, + inner: inner.transition_fulfilled_swap_order(swap)?, + }), + } } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index fd4845ca82..9f28e6e742 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -218,7 +218,6 @@ pub mod pallet { RedeemState, >; - // TODO: How to deal with `RedeemState` here? /// Maps `TokenSwapOrders` to `InvestmentInfo` to implicitly enable mapping /// to `InvestmentState`. /// @@ -275,6 +274,7 @@ pub mod pallet { /// /// NOTE: We must ensure, this can practically never happen! InvestmentInfoNotFound, + // TODO: Not used at the moment /// Failed to retrieve the `RedemptionInfo` from the given /// `TokenSwapOrderId`. /// @@ -285,6 +285,7 @@ pub mod pallet { /// /// NOTE: We must ensure, this can practically never happen! TokenSwapReasonNotFound, + // TODO: Not used at the moment /// Failed to determine whether the corresponding currency can be either /// used for payment or payout of an investment. /// diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 5ca607ae36..f02456a879 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -145,7 +145,9 @@ pub enum InvestState< }, } -// TODO: Docs +/// Reflects all state transitions of an `InvestmentState` which can be +/// externally triggered, i.e. by (partially) fulfilling a token swap order or +/// updating an unprocessed investment. #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum InvestTransition< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, @@ -196,10 +198,15 @@ pub enum RedeemState< Invested { invest_amount: Balance }, /// There is no remaining investment such that the redemption cannot be /// increased at this point. - NotInvestedAnd(InnerRedeemState), + NotInvestedAnd { + inner: InnerRedeemState, + }, /// There is a remaining invested amount such that the redemption can be /// increased up to the remaining invested amount (after fulfillment). - InvestedAnd(InnerRedeemState), + InvestedAnd { + invest_amount: Balance, + inner: InnerRedeemState, + }, } /// Reflects all possible redeem states independent of whether an investment is @@ -326,20 +333,9 @@ pub enum InnerRedeemState< }, } -// TODO: -// #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, -// TypeInfo, MaxEncodedLen)] pub(crate) struct DeconstructedRedeemState where -// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, -// Currency: Clone + Copy + PartialEq, { -// pub(crate) swap: Swap, -// pub(crate) done_amount: Some(Balance), -// pub(crate) collectable_amount: Swap, -// pub(crate) redeem_amount: Swap, -// pub(crate) is_invested: bool, -// } - -// TODO: Docs +/// Reflects all state transitions of a `RedeemState` which can be +/// externally triggered, i.e. by (partially) fulfilling a token swap order or +/// updating an unprocessed redemption. #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RedeemTransition< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, From 2cce2aad0aee258a2ed7c4ef690d96efe586d11a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 10 Aug 2023 18:15:10 +0200 Subject: [PATCH 13/96] feat: redeem storage updates, init more hooks --- libs/types/src/investments.rs | 2 +- pallets/foreign-investments/src/impls/mod.rs | 310 ++++++++++++++---- .../foreign-investments/src/impls/redeem.rs | 127 ++++++- pallets/foreign-investments/src/lib.rs | 16 +- 4 files changed, 381 insertions(+), 74 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index a5051d0ecc..fb117dd6d7 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -67,7 +67,7 @@ pub struct ForeignInvestmentInfo { #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ExecutedDecrease { - pub amount_payout: Balance, + pub amount_decreased: Balance, pub amount_remaining: Balance, } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 40ce1c0b24..e6b3f5980e 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -12,7 +12,7 @@ // GNU General Public License for more details. use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; -use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; +use cfg_types::investments::{ExecutedCollect, ExecutedDecrease, InvestmentInfo}; use frame_support::{traits::Get, transactional}; use sp_runtime::{ traits::{EnsureAdd, Zero}, @@ -148,12 +148,16 @@ impl ForeignInvestment for Pallet { pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount - pre_amount)) } else if amount < pre_amount { // safe because amount < pre_amount - pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount)) + let post_state = + pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount))?; + // notify about reduction + Self::notify_executed_decrease_redeem(who, investment_id, amount)?; + Ok(post_state) } else { Ok(pre_state) }?; - // Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; + Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(()) } @@ -178,12 +182,6 @@ impl ForeignInvestment for Pallet { } impl Pallet { - // fn pre_state_transition_invest( - // who: &T::AccountId, - // investment_id: T::InvestmentId, - // state: InvestState, - // ) -> DispatchResult { - /// Applies in-memory transitions of `InvestState` to chain storage. Always /// updates/removes `InvestmentState` and the current investment. Depending /// on the state, also kills/updates the current token swap order as well as @@ -207,106 +205,85 @@ impl Pallet { /// 4. If the token swap handling resulted in a new `InvestState`, update /// `InvestmentState` again. /// - /// 5. If the token swap handling resulted in a new `RedemptionState`, + /// 5. If the token swap handling resulted in a new `RedeemState`, /// update `RedemptionState`. /// /// 6. Update the investment. This also includes setting it to zero. We - /// assume the impl of `T::Investment` handles this case. + /// assume the impl of `::Investment` handles this case. /// /// NOTES: /// * Must be called after transitioning any `InvestState` via /// `transition` to update the chain storage. /// * When updating token swap orders, only `handle_swap_order` should - /// be called + /// be called. #[transactional] - // TODO: Add/adjust apply_invest_state_transition for redeem orders fn apply_invest_state_transition( who: &T::AccountId, investment_id: T::InvestmentId, state: InvestState, ) -> DispatchResult { - let invest_amount = match state.clone() { + match state.clone() { InvestState::NoState => { InvestmentState::::remove(who, investment_id); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) + Ok((None, Zero::zero())) }, InvestState::InvestmentOngoing { invest_amount } => { InvestmentState::::insert(who, investment_id, state); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) + Ok((None, invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrency { swap } | InvestState::ActiveSwapIntoReturnCurrency { swap } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { InvestmentState::::insert(who, investment_id, state); - - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) + Ok((Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { InvestmentState::::insert(who, investment_id, state); - - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap), TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) + Ok((Some(swap), invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_amount)?; let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; InvestmentState::::insert(who, investment_id, new_state); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order( - who, - investment_id, - Some(swap.clone()), - TokenSwapReason::Investment, - )?; - - Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) + Ok((Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::send_executed_decrease_hook(who, investment_id, done_amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_amount)?; let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; InvestmentState::::insert(who, investment_id, new_state); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, Some(swap.clone()), TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) + Ok((Some(swap), invest_amount)) }, InvestState::SwapIntoReturnDone { done_swap } => { - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount)?; InvestmentState::::remove(who, investment_id); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, Zero::zero(), maybe_redeem_state)) + Ok((None, Zero::zero())) }, InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { - Self::send_executed_decrease_hook(who, investment_id, done_swap.amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount)?; let new_state = InvestState::InvestmentOngoing { invest_amount }; InvestmentState::::insert(who, investment_id, new_state); - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order(who, investment_id, None, TokenSwapReason::Investment)?; - - Ok((maybe_invest_state, invest_amount, maybe_redeem_state)) + Ok((None, invest_amount)) }, } - // update invest and redeem states if necessary - .map(|(maybe_invest_state, invest_amount, maybe_redeem_state)| { + .map(|(maybe_swap, invest_amount)| { + let (maybe_invest_state, maybe_redeem_state) = + Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; + + // update invest and redeem states if necessary InvestmentState::::mutate(who, investment_id, |current_invest_state| { if maybe_invest_state != *current_invest_state { *current_invest_state = maybe_invest_state; @@ -321,13 +298,136 @@ impl Pallet { } }); - invest_amount - }).map_err(|e: DispatchError| e)?; + // Finally, update investment after all states have been updated + T::Investment::update_investment(who, investment_id, invest_amount)?; - // Finally, update investment after all states have been updated - T::Investment::update_investment(who, investment_id, invest_amount)?; + Ok(()) + }) + .map_err(|e: DispatchError| e)? + } - Ok(()) + /// Applies in-memory transitions of `RedeemState` to chain storage. Always + /// updates/removes `RedemptionState` and the current redemption. Depending + /// on the state, also kills/updates the current token swap order. + /// + /// The following execution order must not be changed: + /// + /// 1. If the `RedeemState` includes `SwapIntoReturnDone` without + /// `ActiveSwapIntoReturnCurrency`, remove the `SwapIntoReturnDone` part or + /// kill it. + /// + /// 2. Update the `RedemptionState` storage. This step is required as the + /// next step reads this storage entry. + /// + /// 3. Handle the token swap order by either creating, updating or killing + /// it. Depending on the current swap order and the previous and current + /// reason to update it, both the current `RedemptionState` as well as + /// `RedemptionState` might require an update. + /// + /// 4. If the token swap handling resulted in a new `RedeemState`, update + /// `RedemptionState` again. + /// + /// 5. If the token swap handling resulted in a new `InvestState`, + /// update `InvestmentState`. + /// + /// 6. Update the redemption. This also includes setting it to zero. We + /// assume the impl of `::Investment` handles this case. + /// + /// NOTES: + /// * Must be called after transitioning any `RedeemState` via + /// `transition` to update the chain storage. + /// * When updating token swap orders, only `handle_swap_order` should + /// be called. + #[transactional] + fn apply_redeem_state_transition( + who: &T::AccountId, + investment_id: T::InvestmentId, + state: RedeemState, + ) -> DispatchResult { + let invest_amount = state.get_invest_amount().unwrap_or_default(); + + match state.clone() { + RedeemState::NoState => { + RedemptionState::::remove(who, investment_id); + Ok(None) + } + RedeemState::Invested { .. } => { + RedemptionState::::insert(who, investment_id, state); + Ok(None) + } + RedeemState::InvestedAnd { inner, .. } | RedeemState::NotInvestedAnd { inner } => { + match inner { + InnerRedeemState::Redeeming { .. } | + InnerRedeemState::RedeemingAndCollectableRedemption { .. } | + InnerRedeemState::CollectableRedemption { .. } => { + RedemptionState::::insert(who, investment_id, state); + Ok(None) + }, + InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } | + InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | + InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + InnerRedeemState::ActiveSwapIntoReturnCurrency { swap, .. } | + InnerRedeemState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | + InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { + RedemptionState::::insert(who, investment_id, state); + Ok(Some(swap)) + }, + InnerRedeemState::SwapIntoReturnDone { done_swap } => { + RedemptionState::::remove(who, investment_id); + Ok(None) + }, + // TODO: Check whether we can just remove these four states + InnerRedeemState::RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => { + let new_state = state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); + RedemptionState::::insert(who, investment_id, new_state); + Ok(None) + }, + InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { + let new_state = state.swap_inner_state(InnerRedeemState::RedeemingAndCollectableRedemption { redeem_amount, collect_amount }); + RedemptionState::::insert(who, investment_id, new_state); + Ok(None) + }, + InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { + let new_state = state.swap_inner_state(InnerRedeemState::CollectableRedemption { collect_amount }); + RedemptionState::::insert(who, investment_id, new_state); + Ok(None) + }, + } + } + } + .map(|maybe_swap| { + let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order( + who, + investment_id, + maybe_swap, + TokenSwapReason::Redemption, + )?; + + // update invest and redeem states if necessary + InvestmentState::::mutate(who, investment_id, |current_invest_state| { + if maybe_invest_state != *current_invest_state { + *current_invest_state = maybe_invest_state; + } + // TODO: Maybe emit event of invest state transition from + // `state` to `current_invest_state` + }); + + RedemptionState::::mutate(who, investment_id, |current_redeem_state| { + if maybe_redeem_state != *current_redeem_state { + *current_redeem_state = maybe_redeem_state; + // TODO: Maybe emit event of redeem state transition from + // `current_redeem_state` to `new_state` + } + }); + + // Finally, update redemption after all states have been updated + T::Investment::update_redemption(who, investment_id, invest_amount)?; + + Ok(()) + }) + .map_err(|e: DispatchError| e)? } /// Updates or kills a token swap order. If the final swap amount is zero, @@ -608,26 +708,110 @@ impl Pallet { Ok((token_swap, new_invest_state, new_redeem_state)) } - /// Sends `ExecutedDecreaseHook` notification such that any potential + /// Sends `ExecutedDecreaseInvestHook` notification such that any potential /// consumer could act upon that, e.g. Connectors for - /// `ExecutedDecrease{Invest, Redeem}Order`. - fn send_executed_decrease_hook( + /// `ExecutedDecreaseInvestOrder`. + fn notify_executed_decrease_invest( who: &T::AccountId, investment_id: T::InvestmentId, - amount_payout: T::Balance, + amount_decreased: T::Balance, ) -> DispatchResult { // TODO(@mustermeiszer): Does this return the entire desired amount or do we - // need to tap into collecting? + // need to tap into collecting? > Requires artificial collect (which does not + // mutate state) and then look at order id. + // NOTE: We might change amounts to be deltas. let amount_remaining = T::Investment::investment(who, investment_id)?; // TODO(@mustermeiszer): Do we add the active swap amount? - T::ExecutedDecreaseHook::notify_status_change( + T::ExecutedDecreaseInvestHook::notify_status_change( + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ExecutedDecrease { + amount_decreased, + amount_remaining, + }, + ) + } + + /// Sends `ExecutedDecreaseRedeemHook` notification such that any potential + /// consumer could act upon that, e.g. Connectors for + /// `ExecutedDecreaseRedeemOrder`. + /// + /// NOTE: In contrast to investments, redemption decrements happen + /// fully synchronously as they can only be called in between increasing a + /// redemption and its (full) processing. The asynchronous token swap + /// happens much later. + fn notify_executed_decrease_redeem( + who: &T::AccountId, + investment_id: T::InvestmentId, + amount_decreased: T::Balance, + ) -> DispatchResult { + // TODO: Check if this is correct and sufficient + let amount_remaining = T::Investment::redemption(who, investment_id)?; + + T::ExecutedDecreaseRedeemHook::notify_status_change( ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, }, ExecutedDecrease { - amount_payout, + amount_decreased, + amount_remaining, + }, + ) + } + + /// Sends `ExecutedCollectRedeemHook` notification such that any potential + /// consumer could act upon that, e.g. Connectors for + /// `ExecutedCollectRedeemOrder`. + fn notify_executed_collect_invest( + who: &T::AccountId, + investment_id: T::InvestmentId, + currency: T::CurrencyId, + amount_currency_payout: T::Balance, + ) -> DispatchResult { + // FIXME: Insufficient + let amount_remaining: ::Balance = + T::Investment::investment(who, investment_id)?; + + T::ExecutedCollectInvestHook::notify_status_change( + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ExecutedCollect { + currency, + amount_currency_payout, + amount_tranche_tokens_payout: todo!(), + amount_remaining, + }, + ) + } + + /// Sends `ExecutedCollectRedeemHook` notification such that any potential + /// consumer could act upon that, e.g. Connectors for + /// `ExecutedCollectRedeemOrder`. + fn notify_executed_collect_redeem( + who: &T::AccountId, + investment_id: T::InvestmentId, + currency: T::CurrencyId, + amount_currency_payout: T::Balance, + ) -> DispatchResult { + // TODO: Check if this is correct and sufficient + let amount_remaining: ::Balance = + T::Investment::redemption(who, investment_id)?; + + T::ExecutedCollectRedeemHook::notify_status_change( + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ExecutedCollect { + currency, + amount_currency_payout, + amount_tranche_tokens_payout: todo!(), amount_remaining, }, ) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 11ee354c1d..823bf9c6fb 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -93,6 +93,16 @@ where } } + /// Returns the potentially existing invest amount. + pub(crate) fn get_invest_amount(&self) -> Option { + match self { + Self::Invested { invest_amount } | Self::InvestedAnd { invest_amount, .. } => { + Some(*invest_amount) + } + _ => None, + } + } + /// Exchanges the inner state of `RedeemState::InvestedAnd` as well as /// `RedeemState::NotInvestedAnd` with the provided one similar to a memory /// swap. @@ -481,6 +491,8 @@ where let Swap { amount, .. } = fulfilled_swap; + // edge case: if currency_in matches currency_out, we can immediately fulfill + // the swap match *self { Redeeming { .. } | CollectableRedemption { .. } | @@ -490,7 +502,7 @@ where RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { .. } | CollectableRedemptionAndSwapIntoReturnDone { .. } => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), ActiveSwapIntoReturnCurrency { swap } => { - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) } else { Ok(SwapIntoReturnDone { done_swap: swap }) @@ -498,14 +510,14 @@ where }, ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) } else { Ok(SwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) } }, RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) } else { Ok(RedeemingAndSwapIntoReturnDone { done_swap: swap, redeem_amount }) @@ -513,14 +525,14 @@ where }, RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) } else { Ok(RedeemingAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) } }, RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => { - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount, collect_amount }) } else { Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, redeem_amount, collect_amount }) @@ -528,14 +540,14 @@ where }, RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount, collect_amount }) } else { Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount, collect_amount }) } }, CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, collect_amount }) } else { Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, collect_amount }) @@ -543,7 +555,7 @@ where }, CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount { + if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, collect_amount }) } else { Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, collect_amount }) @@ -551,6 +563,105 @@ where }, } } + + /// Remove `CollectableRedemption` from all states which include it. Either + /// swap it with `ActiveSwapIntoReturnCurrency` if the state did not include + /// an active swap or simply drop it. + /// + /// Throws iff the state includes an active or done swap and either + /// * The in and out currencies do not match the provided ones, or + /// * The collectable amount cannot be incremented by the swap amount + /// (should never happen). + fn transition_collect( + &self, + currency_in: Currency, + currency_out: Currency, + ) -> Result { + ensure!( + self.get_active_swap() + .map(|swap| (swap.currency_in, swap.currency_out) == (currency_in, currency_out)) + .unwrap_or(true), + DispatchError::Other("Invalid swap currencies when transitioning collect redemption") + ); + + match *self { + Redeeming { .. } | + ActiveSwapIntoReturnCurrency { .. } | + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | + SwapIntoReturnDone { .. } | + RedeemingAndActiveSwapIntoReturnCurrency { .. } | + RedeemingAndSwapIntoReturnDone { .. } | + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), + CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { + swap: Swap { + amount: collect_amount, + currency_in, + currency_out + } + }), + RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: Swap { + amount: collect_amount, + currency_in, + currency_out + } + }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: Swap { + amount: swap.amount.ensure_add(collect_amount)?, + ..swap + } + }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: collect_amount, + ..done_swap + }, + done_amount: done_swap.amount + }) + }, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: swap.amount.ensure_add(collect_amount)?, + ..swap + }, + done_amount + }) + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: Swap { + amount: swap.amount.ensure_add(collect_amount)?, + ..swap + } + }) + }, + CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: collect_amount, + ..done_swap + }, + done_amount: done_swap.amount, + }) + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_add(collect_amount)?, + ..swap + }, + done_amount + }) + }, + } + } } // Actual impl of transition diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 9f28e6e742..e5b2d10f85 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -164,13 +164,25 @@ pub mod pallet { OrderId = Self::TokenSwapOrderId, >; - type ExecutedDecreaseHook: StatusNotificationHook< + type ExecutedDecreaseInvestHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, Status = ExecutedDecrease, Error = DispatchError, >; - type ExecutedCollectHook: StatusNotificationHook< + type ExecutedDecreaseRedeemHook: StatusNotificationHook< + Id = ForeignInvestmentInfoOf, + Status = ExecutedDecrease, + Error = DispatchError, + >; + + type ExecutedCollectInvestHook: StatusNotificationHook< + Id = ForeignInvestmentInfoOf, + Status = ExecutedCollect, + Error = DispatchError, + >; + + type ExecutedCollectRedeemHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, Status = ExecutedCollect, Error = DispatchError, From 8cfa18d9a1987b48c59fe2ad51ed47b0478b7ea6 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 11 Aug 2023 18:31:11 +0200 Subject: [PATCH 14/96] feat: collect, update connectors + refactor: ForeignInvestment --- libs/traits/src/lib.rs | 150 ++++++++++---- libs/types/src/investments.rs | 3 +- pallets/connectors/src/inbound.rs | 119 +++++------ pallets/connectors/src/lib.rs | 38 ++-- pallets/foreign-investments/src/impls/mod.rs | 194 ++++++++++-------- .../foreign-investments/src/impls/redeem.rs | 50 ++++- pallets/foreign-investments/src/lib.rs | 2 +- pallets/foreign-investments/src/types.rs | 1 + 8 files changed, 339 insertions(+), 218 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index b78c7b9e44..00a3eb3341 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -394,37 +394,46 @@ pub trait Investment { amount: Self::Amount, ) -> Result<(), Self::Error>; - /// Checks whether a currency can be used for buying `InvestmentId` + /// Checks whether a currency can be used for buying the given investment. fn accepted_payment_currency( investment_id: Self::InvestmentId, currency: Self::CurrencyId, ) -> bool; - /// Returns, if possible, the current investment amount of who into the - /// given investment class + /// Returns, if possible, the current investment amount (in pool currency) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed investment from pool + /// currency into tranche tokens. fn investment( who: &AccountId, investment_id: Self::InvestmentId, ) -> Result; - /// Updates the current redemption amount of who into the - /// investment class to amount. - /// Meaning: if amount < previous redemption, then redemption - /// will be reduced, and increases in the opposite case. + /// Updates the current redemption amount (in tranche tokens) of who into + /// the investment class to amount. + /// Meaning: if amount < previous redemption, then the redemption + /// will be reduced, and increased in the opposite case. + /// + /// NOTE: Redemptions are bound by the processed investment amount. fn update_redemption( who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, ) -> Result<(), Self::Error>; - /// Checks whether a currency is accepted as a payout for an `InvestmentId` + /// Checks whether a currency is accepted as a payout for the given + /// investment. fn accepted_payout_currency( investment_id: Self::InvestmentId, currency: Self::CurrencyId, ) -> bool; - /// Returns, if possible, the current redemption amount of who into the - /// given investment class + /// Returns, if possible, the current redemption amount (in tranche tokens) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed redemption from tranche + /// tokens into pool currency. fn redemption( who: &AccountId, investment_id: Self::InvestmentId, @@ -729,49 +738,68 @@ pub trait TokenSwaps { fn is_active(order: Self::OrderId) -> bool; } +/// Trait to handle investments in (presumably) foreign currencies, i.e., other +/// currencies than the pool currency. +/// +/// NOTE: Has many similarities with the [Investment] trait. pub trait ForeignInvestment { type Amount; type CurrencyId; type Error: Debug; type InvestmentId; - /// Initiates the update of a foreign investment amount in `return_currency` - /// of who into the investment class `pool_currency` to amount. - /// - /// In general, we can assume that return and pool currency mismatch and - /// that swapping one into the other happens asynchronously. In that case, - /// the finalization of updating the investment needs to be handled - /// decoupled from the ForeignInvestment trait. + /// Initiates the increment of a foreign investment amount in + /// `return_currency` of who into the investment class `pool_currency` to + /// amount. /// - /// NOTE: In practice, Consumers such as Connectors should call - /// this function instead of `Investment::update_investment` as this - /// implementation accounts for (potentially) splitting the update into two - /// stages. The second stage is resolved by - /// acting upon `StatusNotificationHook::notify_status_change` which is sent - /// by `TokenSwaps` trait implementor. - fn update_foreign_invest_order( + /// NOTE: In general, we can assume that the return and pool currencies + /// mismatch and that swapping one into the other happens asynchronously. In + /// that case, the finalization of updating the investment needs to be + /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. + fn increase_foreign_investment( who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, return_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, + ) -> Result<(), Self::Error>; + + /// Initiates the decrement of a foreign investment amount in + /// `return_currency` of who into the investment class `pool_currency` to + /// amount. + /// + /// NOTE: In general, we can assume that the return and pool currencies + /// mismatch and that swapping one into the other happens asynchronously. In + /// that case, the finalization of updating the investment needs to be + /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. + fn decrease_foreign_investment( + who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; - /// Initiates the update of a foreign redemption amount from `pool_currency` - /// of who into `return_currency` to amount. + /// Initiates the increment of a foreign redemption amount from + /// `pool_currency` of who into `return_currency` to amount. /// - /// In general, we can assume that return and pool currency mismatch and - /// that swapping one into the other happens asynchronously. In that case, - /// the finalization of updating the redemption needs to be handled - /// decoupled from the ForeignInvestment trait. + /// NOTE: The incrementing redemption amount is bound by the processed + /// investment amount. + fn increase_foreign_redemption( + who: &AccountId, + // TODO: Check if we do not require them if can be derived in CollectRedeemOrder + // return_currency: Self::CurrencyId, + // pool_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Initiates the decrement of a foreign redemption amount from + /// `pool_currency` of who into `return_currency` to amount. /// - /// NOTE: In practice, Consumers such as Connectors should call - /// this function instead of `Investment::update_redemption` as this - /// implementation accounts for (potentially) splitting the update into two - /// stages. The second stage is resolved by - /// acting upon `StatusNotificationHook::notify_status_change` which is sent - /// by `TokenSwaps` trait implementor. - fn update_foreign_redemption( + /// NOTE: The decrementing redemption amount is bound by the previously + /// incremented redemption amount. + fn decrease_foreign_redemption( who: &AccountId, // TODO: Check if we do not require them if can be derived in CollectRedeemOrder // return_currency: Self::CurrencyId, @@ -780,21 +808,59 @@ pub trait ForeignInvestment { amount: Self::Amount, ) -> Result<(), Self::Error>; - // TODO: Docs + /// Collect the results of a user's foreign invest orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. fn collect_foreign_investment( who: &AccountId, - return_currency: Self::CurrencyId, - pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, ) -> Result<(), Self::Error>; - // TODO: Docs + /// Collect the results of a user's foreign redeem orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. + /// + /// NOTE: The currency of the collected amount will be `pool_currency` + /// whereas the user eventually wants to receive it in `return_currency`. fn collect_foreign_redemption( who: &AccountId, + investment_id: Self::InvestmentId, return_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, - investment_id: Self::InvestmentId, ) -> Result<(), Self::Error>; + + /// Returns, if possible, the current investment amount (in pool currency) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed investment from pool + /// currency into tranche tokens. + fn investment( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Returns, if possible, the current redemption amount (in tranche tokens) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed redemption from tranche + /// tokens into pool currency. + fn redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Checks whether a currency can be used for buying the given investment. + fn accepted_payment_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; + + /// Checks whether a currency is accepted as a payout for the given + /// investment. + fn accepted_payout_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; } pub trait StatusNotificationHook { diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index fb117dd6d7..cbcaaf8580 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -75,7 +75,8 @@ pub struct ExecutedDecrease { #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ExecutedCollect { - pub currency: Currency, + // TODO: Check if necessary or can be used better + pub currency: Option, pub amount_currency_payout: Balance, pub amount_tranche_tokens_payout: Balance, pub amount_remaining: Balance, diff --git a/pallets/connectors/src/inbound.rs b/pallets/connectors/src/inbound.rs index 8879a1f908..af240de160 100644 --- a/pallets/connectors/src/inbound.rs +++ b/pallets/connectors/src/inbound.rs @@ -11,7 +11,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{Investment, InvestmentCollector, Permissions}; +use cfg_traits::{ForeignInvestment, Permissions, PoolInspect}; use cfg_types::{ domain_address::{Domain, DomainAddress}, permissions::{PermissionScope, PoolRole, Role}, @@ -21,7 +21,7 @@ use frame_support::{ traits::fungibles::{Mutate, Transfer}, }; use sp_runtime::{ - traits::{Convert, EnsureAdd, EnsureSub, Zero}, + traits::{Convert, Zero}, DispatchResult, }; @@ -92,19 +92,21 @@ impl Pallet { currency_index: GeneralCurrencyIndexOf, amount: ::Balance, ) -> DispatchResult { - // Retrieve investment details let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let pool_currency = + T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; - // Determine post adjustment amount - let pre_amount = T::ForeignInvestment::investment(&investor, invest_id.clone())?; - let post_amount = pre_amount.ensure_add(amount)?; + // Mint additional amount of payment currency + T::Tokens::mint_into(payment_currency, &investor, amount)?; - // Mint additional amount - T::Tokens::mint_into(currency, &investor, amount)?; - - // TODO: Apply pallet_foreign_investment::ForeignInvestment - T::ForeignInvestment::update_investment(&investor, invest_id, post_amount)?; + T::ForeignInvestment::increase_foreign_investment( + &investor, + invest_id, + amount, + payment_currency, + pool_currency, + )?; Ok(()) } @@ -122,16 +124,18 @@ impl Pallet { currency_index: GeneralCurrencyIndexOf, amount: ::Balance, ) -> DispatchResult { - // Retrieve investment details let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let _currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let pool_currency = + T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; - // Determine post adjustment amount - let pre_amount = T::ForeignInvestment::investment(&investor, invest_id.clone())?; - let post_amount = pre_amount.ensure_sub(amount)?; - - // TODO: Apply pallet_foreign_investment::ForeignInvestment - T::ForeignInvestment::update_investment(&investor, invest_id, post_amount)?; + T::ForeignInvestment::decrease_foreign_investment( + &investor, + invest_id, + amount, + payment_currency, + pool_currency, + )?; // TODO: Handle response `ExecutedDecreaseInvestOrder` message to // source destination which should refund the decreased amount. This includes @@ -139,7 +143,7 @@ impl Pallet { // // NOTES: // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 - // * Should be handled by `pallet-foreign-investments` + // * Should be handled by `pallet-foreign-investment` // * Requires notification of `currency_payout` and `remaining_invest_order` // balances @@ -147,7 +151,8 @@ impl Pallet { } /// Increases an existing redemption order of the investor. - /// + // FIXME: This does not make sense? Once the redemption is processed and collected, the foreign + // investment swaps it into return currency into the investor, not the domainlocator. /// Transfers the decreased redemption amount from the holdings of the /// `DomainLocator` account of origination domain of this message into the /// investor account. @@ -161,27 +166,20 @@ impl Pallet { amount: ::Balance, sending_domain: DomainAddress, ) -> DispatchResult { - // Retrieve investment details let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - - // Determine post adjustment amount - let pre_amount = T::ForeignInvestment::redemption(&investor, invest_id.clone())?; - - // TODO: Apply pallet_foreign_investment::ForeignInvestment - let post_amount = pre_amount.ensure_add(amount)?; - - // Transfer tranche tokens from `DomainLocator` account of origination domain - T::Tokens::transfer( - invest_id.clone().into(), - &Domain::convert(sending_domain.domain()), - &investor, - amount, - false, - )?; - - T::ForeignInvestment::update_redemption(&investor, invest_id, post_amount)?; + T::ForeignInvestment::increase_foreign_redemption(&investor, invest_id, amount)?; Ok(()) + + // TODO: Handle transfer in hook or drop entirely + // // Transfer tranche tokens from `DomainLocator` account of + // origination domain T::Tokens::transfer( + // invest_id.clone().into(), + // &Domain::convert(sending_domain.domain()), + // &investor, + // amount, + // false, + // )?; } /// Decreases an existing redemption order of the investor. @@ -198,30 +196,21 @@ impl Pallet { amount: ::Balance, _sending_domain: DomainAddress, ) -> DispatchResult { - // Retrieve investment details let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - // NOTE: Required for relaying `ExecutedDecreaseRedemption` message - let _currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; - - // Determine post adjustment amount - let pre_amount = T::ForeignInvestment::redemption(&investor, invest_id.clone())?; - let post_amount = pre_amount.ensure_sub(amount)?; + T::ForeignInvestment::decrease_foreign_redemption(&investor, invest_id, amount)?; - // TODO: Apply pallet_foreign_investment::ForeignInvestment - T::ForeignInvestment::update_redemption(&investor, invest_id, post_amount)?; + Ok(()) // TODO: Handle response `ExecutedDecreaseRedemption` message to - // source destination which should refund the decreased amount. This includes - // transferring the amount from the investor to the domain locator account of - // the origination domain. + // source destination which should refund the decreased amount. This + // includes transferring the amount from the investor to the domain + // locator account of the origination domain. // // NOTES: // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 - // * Should be handled by `pallet-foreign-investments` + // * Should be handled by `pallet-foreign-investment` // * Requires notification of `tranche_tokens_payout` and // `remaining_redeem_order` balances - - Ok(()) } /// Collect the results of a user's invest orders for the given investment @@ -234,8 +223,9 @@ impl Pallet { ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - // TODO: Apply pallet_foreign_investment::ForeignInvestment - T::ForeignInvestment::collect_investment(investor, invest_id)?; + T::ForeignInvestment::collect_foreign_investment(&investor, invest_id)?; + + // T::ForeignInvestment::collect_foreign_investment(investor, invest_id, ) // TODO: Handle response `ExecutedCollectInvest` message to // source destination. @@ -254,11 +244,19 @@ impl Pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, + currency_index: GeneralCurrencyIndexOf, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let pool_currency = + T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; - // TODO: Apply pallet_foreign_investment::ForeignInvestment - T::ForeignInvestment::collect_redemption(investor, invest_id)?; + T::ForeignInvestment::collect_foreign_redemption( + &investor, + invest_id, + payment_currency, + pool_currency, + )?; // TODO: Handle response `ExecutedCollectRedeem` message to // source destination. @@ -269,4 +267,7 @@ impl Pallet { Ok(()) } + + // TODO: At some point, some token transfer needs to happen for redemptions and + // decrease investment } diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 9d65bd1284..3196f86fc9 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -83,8 +83,8 @@ pub type GeneralCurrencyIndexOf = pub mod pallet { use cfg_primitives::Moment; use cfg_traits::{ - CurrencyInspect, Investment, InvestmentCollector, Permissions, PoolInspect, - TrancheCurrency, TrancheTokenPrice, + CurrencyInspect, ForeignInvestment, Permissions, PoolInspect, TrancheCurrency, + TrancheTokenPrice, }; use cfg_types::{ permissions::{PermissionScope, PoolRole, Role}, @@ -188,23 +188,15 @@ pub mod pallet { + Into> + Clone; - /// Enables investing and redeeming into investment classes. - /// - /// NOTE: For the time being, `pallet_investments` serves as the - /// implementor. However, eventually this should be provided by - /// `pallet_foreign_investments`. - type ForeignInvestment: Investment< - Self::AccountId, - Amount = ::Balance, - CurrencyId = CurrencyIdOf, - Error = DispatchError, - InvestmentId = ::TrancheCurrency, - > + InvestmentCollector< - Self::AccountId, - Error = DispatchError, - InvestmentId = ::TrancheCurrency, - Result = (), - >; + /// Enables investing and redeeming into investment classes with foreign + /// currencies. + type ForeignInvestment: ForeignInvestment< + Self::AccountId, + Amount = ::Balance, + CurrencyId = CurrencyIdOf, + Error = DispatchError, + InvestmentId = ::TrancheCurrency, + >; /// The source of truth for the transferability of assets via /// Connectors. @@ -891,7 +883,13 @@ pub mod pallet { pool_id, tranche_id, investor, - } => Self::handle_collect_redemption(pool_id, tranche_id, investor.into()), + currency, + } => Self::handle_collect_redemption( + pool_id, + tranche_id, + investor.into(), + currency.into(), + ), _ => Err(Error::::InvalidIncomingMessage.into()), }?; diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index e6b3f5980e..d0ac4f1b77 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -11,7 +11,9 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; +use cfg_traits::{ + ForeignInvestment, Investment, InvestmentCollector, StatusNotificationHook, TokenSwaps, +}; use cfg_types::investments::{ExecutedCollect, ExecutedDecrease, InvestmentInfo}; use frame_support::{traits::Get, transactional}; use sp_runtime::{ @@ -50,41 +52,15 @@ impl StatusNotificationHook for Pallet { match reason { TokenSwapReason::Investment => { let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); - let post_state = pre_state - .transition(InvestTransition::FulfillSwapOrder(status)) - .map_err(|e| { - log::debug!( - "Encountered unexpected pre state {:?} when transitioning into {:?} \ - after (partially) fulfilling a swap", - pre_state, - status - ); - e - })?; - Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state.clone()) - .map(|e| { - log::debug!( - "Encountered unexpected error when applying state transition to state \ - {:?}", - post_state - ); - e - }) + let post_state = + pre_state.transition(InvestTransition::FulfillSwapOrder(status))?; + Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) } TokenSwapReason::Redemption => { let pre_state = RedemptionState::::get(&info.owner, info.id).unwrap_or_default(); - let post_state = pre_state - .transition(RedeemTransition::FulfillSwapOrder(status)) - .map_err(|e| { - log::debug!( - "Encountered unexpected pre state {:?} when transitioning into {:?} \ - after (partially) fulfilling a swap", - pre_state, - status - ); - e - })?; - todo!("apply_redeem_state_transition") + let post_state = + pre_state.transition(RedeemTransition::FulfillSwapOrder(status))?; + Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) } } } @@ -96,44 +72,60 @@ impl ForeignInvestment for Pallet { type Error = DispatchError; type InvestmentId = T::InvestmentId; - // Consumers such as Connectors should call this function instead of - // `Investment::update_invest_order` as this implementation accounts for - // (potentially) splitting the update into two stages. The second stage is - // resolved by `StatusNotificationHook::notify_status_change`. - fn update_foreign_invest_order( + fn increase_foreign_investment( who: &T::AccountId, + investment_id: T::InvestmentId, + amount: T::Balance, return_currency: T::CurrencyId, pool_currency: T::CurrencyId, + ) -> Result<(), DispatchError> { + let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + amount, + }))?; + + Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + fn decrease_foreign_investment( + who: &T::AccountId, investment_id: T::InvestmentId, amount: T::Balance, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_amount = T::Investment::investment(who, investment_id.clone())?; let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); - - let post_state = if amount > pre_amount { - pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { - currency_in: pool_currency, - currency_out: return_currency, - // safe because amount > pre_amount - amount: amount - pre_amount, - })) - } else if amount < pre_amount { - pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { - currency_in: return_currency, - currency_out: pool_currency, - // safe because amount < pre_amount - amount: pre_amount - amount, - })) - } else { - Ok(pre_state) - }?; + let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + amount, + }))?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) } - fn update_foreign_redemption( + fn increase_foreign_redemption( + who: &T::AccountId, + // return_currency: T::CurrencyId, + // pool_currency: T::CurrencyId, + investment_id: T::InvestmentId, + amount: T::Balance, + ) -> Result<(), DispatchError> { + let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let post_state = pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount))?; + + Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + fn decrease_foreign_redemption( who: &T::AccountId, // return_currency: T::CurrencyId, // pool_currency: T::CurrencyId, @@ -142,42 +134,76 @@ impl ForeignInvestment for Pallet { ) -> Result<(), DispatchError> { let pre_amount = T::Investment::redemption(who, investment_id.clone())?; let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let post_state = + pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount))?; - let post_state = if amount > pre_amount { - // safe because amount > pre_amount - pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount - pre_amount)) - } else if amount < pre_amount { - // safe because amount < pre_amount - let post_state = - pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount))?; - // notify about reduction - Self::notify_executed_decrease_redeem(who, investment_id, amount)?; - Ok(post_state) - } else { - Ok(pre_state) - }?; + Self::notify_executed_decrease_redeem(who, investment_id, amount)?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(()) } + // TODO: check if this should be transactional fn collect_foreign_investment( who: &T::AccountId, - return_currency: T::CurrencyId, - pool_currency: T::CurrencyId, investment_id: T::InvestmentId, ) -> Result<(), DispatchError> { - todo!() + // No need to transition or update state as collection of tranche tokens is + // independent of the current `InvestState` + let amount_collected = T::Investment::collect_investment(who.clone(), investment_id)?; + Self::notify_executed_collect_invest(who, investment_id, amount_collected) } fn collect_foreign_redemption( who: &T::AccountId, + investment_id: T::InvestmentId, return_currency: T::CurrencyId, pool_currency: T::CurrencyId, - investment_id: T::InvestmentId, ) -> Result<(), DispatchError> { - todo!() + // Transition state to initiate swap from pool to return currency + let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let post_state = + pre_state.transition(RedeemTransition::Collect(return_currency, pool_currency))?; + + let amount_collected = T::Investment::collect_redemption(who.clone(), investment_id)?; + Self::notify_executed_collect_redeem( + who, + investment_id, + return_currency, + amount_collected, + )?; + + Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + fn investment( + who: &T::AccountId, + investment_id: T::InvestmentId, + ) -> Result { + T::Investment::investment(who, investment_id) + } + + fn redemption( + who: &T::AccountId, + investment_id: T::InvestmentId, + ) -> Result { + T::Investment::redemption(who, investment_id) + } + + // TODO: Maybe add pool_currency derived via + // PoolInspect::currency_for(investment_id.into()) + + fn accepted_payment_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { + // FIXME: Check whether order can be created for pair (payment, pool) + T::Investment::accepted_payment_currency(investment_id, currency) + } + + fn accepted_payout_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { + // FIXME: Check whether order can be created for pair (pool, payment) + T::Investment::accepted_payout_currency(investment_id, currency) } } @@ -442,8 +468,7 @@ impl Pallet { /// Returns potentially altered invest and redeem states which are not /// updated in storage yet! /// - /// NOTE: Should be the only swap order updating function which should be - /// called. + /// NOTE: Must not call any other swap order updating function. fn handle_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, @@ -769,8 +794,7 @@ impl Pallet { fn notify_executed_collect_invest( who: &T::AccountId, investment_id: T::InvestmentId, - currency: T::CurrencyId, - amount_currency_payout: T::Balance, + amount_tranche_tokens_payout: T::Balance, ) -> DispatchResult { // FIXME: Insufficient let amount_remaining: ::Balance = @@ -782,9 +806,9 @@ impl Pallet { id: investment_id, }, ExecutedCollect { - currency, - amount_currency_payout, - amount_tranche_tokens_payout: todo!(), + currency: None, + amount_currency_payout: todo!("needs to be derived from processing"), + amount_tranche_tokens_payout, amount_remaining, }, ) @@ -809,9 +833,9 @@ impl Pallet { id: investment_id, }, ExecutedCollect { - currency, + currency: Some(currency), amount_currency_payout, - amount_tranche_tokens_payout: todo!(), + amount_tranche_tokens_payout: todo!("needs to be derived from processing"), amount_remaining, }, ) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 823bf9c6fb..0b3a9b0e56 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -61,6 +61,9 @@ where RedeemTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(&self, swap) } + RedeemTransition::Collect(return_currency, pool_currency) => { + Self::handle_collect(&self, return_currency, pool_currency) + } } } @@ -93,7 +96,8 @@ where } } - /// Returns the potentially existing invest amount. + /// Returns the potentially existing invest, i.e. the upper redemption + /// bound. pub(crate) fn get_invest_amount(&self) -> Option { match self { Self::Invested { invest_amount } | Self::InvestedAnd { invest_amount, .. } => { @@ -568,18 +572,19 @@ where /// swap it with `ActiveSwapIntoReturnCurrency` if the state did not include /// an active swap or simply drop it. /// - /// Throws iff the state includes an active or done swap and either + /// Throws if the state includes an active or done swap and either /// * The in and out currencies do not match the provided ones, or /// * The collectable amount cannot be incremented by the swap amount /// (should never happen). fn transition_collect( &self, - currency_in: Currency, - currency_out: Currency, + return_currency: Currency, + pool_currency: Currency, ) -> Result { ensure!( self.get_active_swap() - .map(|swap| (swap.currency_in, swap.currency_out) == (currency_in, currency_out)) + .map(|swap| (swap.currency_in, swap.currency_out) + == (return_currency, pool_currency)) .unwrap_or(true), DispatchError::Other("Invalid swap currencies when transitioning collect redemption") ); @@ -595,16 +600,16 @@ where CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { swap: Swap { amount: collect_amount, - currency_in, - currency_out + currency_in: return_currency, + currency_out: pool_currency, } }), RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap: Swap { amount: collect_amount, - currency_in, - currency_out + currency_in: return_currency, + currency_out: pool_currency, } }), RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { @@ -789,7 +794,7 @@ where ) -> Result { match self { Self::NoState | Self::Invested { .. } => Err(DispatchError::Other( - "Invalid invest state when transitioning a fulfilled order", + "Invalid redeem state when transitioning a fulfilled order", )), Self::NotInvestedAnd { inner } => Ok(Self::NotInvestedAnd { inner: inner.transition_fulfilled_swap_order(swap)?, @@ -803,4 +808,29 @@ where }), } } + + /// Remove `CollectableRedemption` from all inner states which include it. + /// Either swap it with `ActiveSwapIntoReturnCurrency` if the inner state + /// did not include an active swap or simply drop it. + /// + /// Throws if the state does not allow for collection or the the inner state + /// includes an active/done swap with mismatching currencies to the provided + /// ones. + fn handle_collect( + &self, + return_currency: Currency, + pool_currency: Currency, + ) -> Result { + match self { + RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( + "Invalid redeem state when transitioning collect", + )), + RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => { + Ok(Self::swap_inner_state( + &self, + inner.transition_collect(return_currency, pool_currency)?, + )) + } + } + } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index e5b2d10f85..915c8827a2 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -122,7 +122,7 @@ pub mod pallet { Self::AccountId, Error = DispatchError, InvestmentId = Self::InvestmentId, - Result = (), + Result = Self::Balance, >; /// The default sell price limit for token swaps which defines the diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index f02456a879..437897de3f 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -344,4 +344,5 @@ pub enum RedeemTransition< IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), + Collect(Currency, Currency), } From 958a70f6db5fb965b593f7d87adde0d4a5c786ef Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 11 Aug 2023 18:31:38 +0200 Subject: [PATCH 15/96] refactor: return amounts of do_collect_{invest, redeem} --- pallets/investments/src/lib.rs | 78 +++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 0bb9344488..64451f7919 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -24,6 +24,7 @@ use cfg_types::{ orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, pallet_prelude::*, traits::tokens::fungibles::{Inspect, Mutate, Transfer}, }; @@ -509,7 +510,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_collect_invest(who, investment_id) + Self::do_collect_invest(who, investment_id).map(|(_, info)| info) } /// Collect the results of a user's redeem orders for the given @@ -523,7 +524,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_collect_redeem(who, investment_id) + Self::do_collect_redeem(who, investment_id).map(|(_, info)| info) } /// Collect the results of another users invest orders for the given @@ -538,7 +539,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_collect_invest(who, investment_id) + Self::do_collect_invest(who, investment_id).map(|(_, info)| info) } /// Collect the results of another users redeem orders for the given @@ -553,7 +554,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_collect_redeem(who, investment_id) + Self::do_collect_redeem(who, investment_id).map(|(_, info)| info) } } } @@ -686,7 +687,7 @@ where } fn rm_empty(amount: T::Amount, storage_order: &mut Option>, on_not_empty: Event) { - if amount > T::Amount::zero() { + if !amount.is_zero() { Self::deposit_event(on_not_empty); } else { // In this case the user has no active position. @@ -698,16 +699,18 @@ where } } + // TODO: Add amount and if possible currency to return #[allow(clippy::type_complexity)] pub(crate) fn do_collect_invest( who: T::AccountId, investment_id: T::InvestmentId, - ) -> DispatchResultWithPostInfo { + ) -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; InvestOrders::::try_mutate( &who, investment_id, - |maybe_order| -> DispatchResultWithPostInfo { + |maybe_order| -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { + // Exit early if order does not exist let order = if let Some(order) = maybe_order.as_mut() { order } else { @@ -717,8 +720,9 @@ where }); // TODO: Return correct weight // - Accountant::info() + Storage::read() + Storage::write() - return Ok(().into()); + return Ok((Zero::zero(), ().into())); }; + let mut collection = InvestCollection::::from_order(order); let mut collected_ids = Vec::new(); let cur_order_id = InvestOrderId::::get(investment_id); @@ -729,7 +733,7 @@ where cur_order_id, ); - // The current order is not in processing + // Exit early if the current order is not in processing if order.submitted_at() == cur_order_id { Self::deposit_event(Event::::InvestCollectedForNonClearedOrderId { who: who.clone(), @@ -737,7 +741,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok(().into()); + return Ok((order.amount(), ().into())); } for order_id in order.submitted_at()..last_processed_order_id { @@ -772,6 +776,7 @@ where amount, }, ); + let amount_payout = collection.payout_investment_invest; Self::deposit_event(Event::InvestOrdersCollected { investment_id, @@ -786,21 +791,23 @@ where }); // TODO: Actually weight with amount of collects here - Ok(().into()) + Ok((amount_payout, ().into())) }, ) } + // TODO: Add amount and if possible currency to return #[allow(clippy::type_complexity)] pub(crate) fn do_collect_redeem( who: T::AccountId, investment_id: T::InvestmentId, - ) -> DispatchResultWithPostInfo { + ) -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; RedeemOrders::::try_mutate( &who, investment_id, - |maybe_order| -> DispatchResultWithPostInfo { + |maybe_order| -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { + // Exit early if order does not exist let order = if let Some(order) = maybe_order.as_mut() { order } else { @@ -811,8 +818,9 @@ where }); // TODO: Return correct weight // - Accountant::info() + Storage::read() + Storage::write() - return Ok(().into()); + return Ok((Zero::zero(), ().into())); }; + let mut collection = RedeemCollection::::from_order(order); let mut collected_ids = Vec::new(); let cur_order_id = RedeemOrderId::::get(investment_id); @@ -823,7 +831,7 @@ where cur_order_id, ); - // The current order is not in processing + // Exit early if the current order is not in processing if order.submitted_at() == cur_order_id { Self::deposit_event(Event::::RedeemCollectedForNonClearedOrderId { who: who.clone(), @@ -831,7 +839,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok(().into()); + return Ok((order.amount(), ().into())); } for order_id in order.submitted_at()..last_processed_order_id { @@ -854,6 +862,7 @@ where info.payment_currency(), &investment_account, &who, + // TODO: return collected amount collection.payout_investment_redeem, false, )?; @@ -869,6 +878,7 @@ where amount, }, ); + let amount_payout = collection.payout_investment_redeem; Self::deposit_event(Event::RedeemOrdersCollected { investment_id, @@ -883,7 +893,7 @@ where }); // TODO: Actually weight this with collected_ids - Ok(().into()) + Ok((amount_payout, ().into())) }, ) } @@ -971,16 +981,16 @@ where ) -> DispatchResult { let remaining = collection.remaining_investment_invest; // NOTE: The checked_mul_int_floor and reciprocal_floor here ensure that for a - // given price the system side (i.e. the pallet-investments) will always - // have enough balance to satisfy all claims on payouts. + // given price the system side (i.e. the pallet-investments) will always + // have enough balance to satisfy all claims on payouts. // - // Importantly, the Accountant side (i.e. the pool and therefore an - // issuer) will still drain its reserve by the amount without rounding. So - // we neither favor issuer or investor but always the system. + // Importantly, the Accountant side (i.e. the pool and therefore an issuer) will + // still drain its reserve by the amount without rounding. So we neither favor + // issuer or investor but always the system. // - // TODO: Rounding always means, we might have issuance on tranche-tokens - // left, that are rounding leftovers. This will be of importance, - // once we remove tranches at some point. + // TODO: Rounding always means, we might have issuance on tranche-tokens + // left, that are rounding leftovers. This will be of importance, once we remove + // tranches at some point. collection.payout_investment_invest = collection .payout_investment_invest .checked_add( @@ -1005,13 +1015,13 @@ where // the system side (i.e. the pallet-investments) will always have // enough balance to satisfy all claims on payouts. // - // Importantly, the Accountant side (i.e. the pool and therefore an - // issuer) will still drain its reserve by the amount without rounding. So - // we neither favor issuer or investor but always the system. + // Importantly, the Accountant side (i.e. the pool and therefore an issuer) will + // still drain its reserve by the amount without rounding. So we neither favor + // issuer or investor but always the system. // - // TODO: Rounding always means, we might have issuance on tranche-tokens - // left, that are rounding leftovers. This will be of importance, - // once we remove tranches at some point. + // TODO: Rounding always means, we might have issuance on tranche-tokens left, + // that are rounding leftovers. This will be of importance, once we remove + // tranches at some point. collection.payout_investment_redeem = collection .payout_investment_redeem .checked_add( @@ -1432,7 +1442,7 @@ where { type Error = DispatchError; type InvestmentId = T::InvestmentId; - type Result = (); + type Result = T::Amount; fn collect_investment( who: T::AccountId, @@ -1440,7 +1450,7 @@ where ) -> Result { Pallet::::do_collect_invest(who, investment_id) .map_err(|e| e.error) - .map(|_| ()) + .map(|(amount, _)| amount) } fn collect_redemption( @@ -1449,6 +1459,6 @@ where ) -> Result { Pallet::::do_collect_redeem(who, investment_id) .map_err(|e| e.error) - .map(|_| ()) + .map(|(amount, _)| amount) } } From 94ff978712a305148ec18669c1b58680db233856 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 11 Aug 2023 18:31:56 +0200 Subject: [PATCH 16/96] refactor: add payout currency to CollectRedeem msg --- pallets/connectors/src/message.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 65871badf3..9669b0863b 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -199,6 +199,7 @@ where pool_id: PoolId, tranche_id: TrancheId, investor: Address, + currency: u128, }, /// The message sent back to the domain from which a `DecreaseInvestOrder` /// message was received, ensuring the correct state update on said domain @@ -263,6 +264,7 @@ where tranche_tokens_payout: Balance, /// The remaining amount of `currency` the investor still has locked to /// invest at a later epoch execution + // TODO: Should be MORE than Investment::investment(who, investment_id) remaining_invest_order: Balance, }, /// The message sent back to the domain from which a `CollectRedeem` message @@ -501,9 +503,15 @@ impl< pool_id, tranche_id, investor, + currency, } => encoded_message( self.call_type(), - vec![encode_be(pool_id), tranche_id.encode(), investor.to_vec()], + vec![ + encode_be(pool_id), + tranche_id.encode(), + investor.to_vec(), + encode_be(currency), + ], ), Message::ExecutedDecreaseInvestOrder { pool_id, @@ -670,6 +678,7 @@ impl< pool_id: decode_be_bytes::<8, _, _>(input)?, tranche_id: decode::<16, _, _>(input)?, investor: decode::<32, _, _>(input)?, + currency: decode_be_bytes::<16, _, _>(input)?, }), 15 => Ok(Self::ExecutedDecreaseInvestOrder { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -1011,8 +1020,9 @@ mod tests { pool_id: POOL_ID, tranche_id: default_tranche_id(), investor: default_address_32(), + currency: TOKEN_ID }, - "0e0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b4564564564564564564564564564564564564564564564564564564564564564", + "0e0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b", ) } From 72fc5dbb1557858e4689093b106b2633ddcbc944 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 11 Aug 2023 18:32:32 +0200 Subject: [PATCH 17/96] wip: add ForeignInvestments to dev runtime --- Cargo.lock | 3 +- pallets/foreign-investments/Cargo.toml | 2 +- runtime/development/Cargo.toml | 4 +++ runtime/development/src/lib.rs | 42 ++++++++++++++++++++++++-- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bed14254b5..6d21b552f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2655,6 +2655,7 @@ dependencies = [ "pallet-evm-chain-id", "pallet-evm-precompile-dispatch", "pallet-fees", + "pallet-foreign-investment", "pallet-identity", "pallet-interest-accrual", "pallet-investments", @@ -7317,7 +7318,7 @@ dependencies = [ ] [[package]] -name = "pallet-foreign-investments" +name = "pallet-foreign-investment" version = "1.0.0" dependencies = [ "cfg-primitives", diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml index d07585ef4d..293ea147bd 100644 --- a/pallets/foreign-investments/Cargo.toml +++ b/pallets/foreign-investments/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Centrifuge "] description = "Pallet to enable investments and redemptions via a foreign interface" edition = "2021" license = "LGPL-3.0" -name = "pallet-foreign-investments" +name = "pallet-foreign-investment" repository = "https://github.com/centrifuge/centrifuge-chain" version = "1.0.0" diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index ba8382baf6..10a01cca2e 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -122,6 +122,7 @@ pallet-crowdloan-claim = { path = "../../pallets/crowdloan-claim", default-featu pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-features = false } pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } +pallet-foreign-investment = { path = "../../pallets/foreign-investments", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-keystore = { path = "../../pallets/keystore", default-features = false } @@ -196,6 +197,7 @@ std = [ "pallet-evm-precompile-dispatch/std", "pallet-evm-chain-id/std", "pallet-fees/std", + "pallet-foreign-investment/std", "pallet-identity/std", "pallet-interest-accrual/std", "pallet-investments/std", @@ -283,6 +285,7 @@ runtime-benchmarks = [ "pallet-ethereum/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", + # "pallet-foreign-investment/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", "pallet-keystore/runtime-benchmarks", @@ -381,6 +384,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-fees/try-runtime", + "pallet-foreign-investment/try-runtime", "pallet-identity/try-runtime", "pallet-migration-manager/try-runtime", "pallet-multisig/try-runtime", diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 3dc53efd9e..d7ac4435c2 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -104,7 +104,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, - Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, + Dispatchable, One, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, FixedI128, Perbill, Permill, @@ -1561,6 +1561,43 @@ impl orml_asset_registry::Config for Runtime { type WeightInfo = (); } +parameter_types! { + // TODO: Discuss, refine + pub const DefaultTokenMinFulfillmentAmount: Balance = Balance::one(); + pub const DefaultTokenSwapSellPriceLimit: Balance = Balance::one(); +} + +// TODO: Remove me +struct DummyHook; +impl cfg_traits::StatusNotificationHook for DummyHook { + type Error = DispatchError; + type Id = u128; + type Status = (); + + fn notify_status_change(id: u128, status: ()) -> Result<(), DispatchError> { + unimplemented!("Remove the entire impl before merging") + } +} + +impl pallet_foreign_investment::Config for Runtime { + type Balance = Balance; + type CurrencyId = CurrencyId; + type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; + type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; + type ExecutedCollectInvestHook = DummyHook; + type ExecutedCollectRedeemHook = DummyHook; + type ExecutedDecreaseInvestHook = DummyHook; + type ExecutedDecreaseRedeemHook = DummyHook; + type Investment = Investments; + type InvestmentId = TrancheCurrency; + type PoolId = PoolId; + type RuntimeEvent = RuntimeEvent; + type TokenSwapOrderId = u128; + type TokenSwaps = (); + type TrancheId = TrancheId; + type WeightInfo = (); +} + pub struct DummyOutboundQueue; impl cfg_traits::connectors::OutboundQueue for DummyOutboundQueue { @@ -1583,7 +1620,7 @@ impl pallet_connectors::Config for Runtime { type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type CurrencyId = CurrencyId; - type ForeignInvestment = Investments; + type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::connectors::GeneralCurrencyPrefix; type OutboundQueue = DummyOutboundQueue; type Permission = Permissions; @@ -1911,6 +1948,7 @@ construct_runtime!( TransferAllowList: pallet_transfer_allowlist::{Pallet, Call, Storage, Event} = 112, PriceCollector: pallet_data_collector::{Pallet, Storage} = 113, GapRewardMechanism: pallet_rewards::mechanism::gap = 114, + ForeignInvestments: pallet_foreign_investment::{Pallet, Call, Storage, Event} = 115, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, From 69de4bb58f3f922232bfedf2416790d9648c0e7e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 16 Aug 2023 21:46:55 +0200 Subject: [PATCH 18/96] wip: collect, hooks, transition events, refactoring --- Cargo.lock | 4 +- libs/traits/src/investments.rs | 398 ++++++++++++++ libs/traits/src/lib.rs | 391 +------------ libs/types/src/investments.rs | 152 +++++- libs/types/src/tokens.rs | 12 +- pallets/connectors/src/hooks.rs | 107 ++++ pallets/connectors/src/inbound.rs | 172 +++--- pallets/connectors/src/lib.rs | 22 +- pallets/connectors/src/message.rs | 19 +- pallets/foreign-investments/Cargo.toml | 2 +- pallets/foreign-investments/src/impls/mod.rs | 493 +++++++++++------ .../foreign-investments/src/impls/redeem.rs | 110 ++-- pallets/foreign-investments/src/lib.rs | 64 ++- pallets/foreign-investments/src/types.rs | 2 +- pallets/investments/src/lib.rs | 516 ++++++++---------- pallets/investments/src/tests.rs | 84 ++- pallets/pool-registry/src/lib.rs | 2 +- pallets/pool-system/src/impls.rs | 5 +- pallets/pool-system/src/lib.rs | 5 +- pallets/pool-system/src/pool_types.rs | 2 +- pallets/pool-system/src/tranches.rs | 2 +- runtime/altair/src/lib.rs | 4 +- runtime/centrifuge/src/lib.rs | 4 +- runtime/common/src/lib.rs | 2 +- runtime/development/Cargo.toml | 8 +- runtime/development/src/lib.rs | 37 +- 26 files changed, 1503 insertions(+), 1116 deletions(-) create mode 100644 libs/traits/src/investments.rs create mode 100644 pallets/connectors/src/hooks.rs diff --git a/Cargo.lock b/Cargo.lock index c25be2c470..8aee4b0ccb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2694,7 +2694,7 @@ dependencies = [ "pallet-evm-chain-id", "pallet-evm-precompile-dispatch", "pallet-fees", - "pallet-foreign-investment", + "pallet-foreign-investments", "pallet-identity", "pallet-interest-accrual", "pallet-investments", @@ -7473,7 +7473,7 @@ dependencies = [ ] [[package]] -name = "pallet-foreign-investment" +name = "pallet-foreign-investments" version = "1.0.0" dependencies = [ "cfg-primitives", diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs new file mode 100644 index 0000000000..beba64be44 --- /dev/null +++ b/libs/traits/src/investments.rs @@ -0,0 +1,398 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. + +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). + +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +use sp_std::fmt::Debug; + +/// A trait for converting from a PoolId and a TranchId +/// into a given Self::Currency +pub trait TrancheCurrency { + fn generate(pool_id: PoolId, tranche_id: TrancheId) -> Self; + + fn of_pool(&self) -> PoolId; + + fn of_tranche(&self) -> TrancheId; +} + +/// A trait, when implemented allows to invest into +/// investment classes +pub trait Investment { + type Amount; + type CurrencyId; + type Error: Debug; + type InvestmentId; + + /// Updates the current investment amount of who into the + /// investment class to amount. + /// Meaning: if amount < previous investment, then investment + /// will be reduced, and increases in the opposite case. + fn update_investment( + who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Checks whether a currency can be used for buying the given investment. + fn accepted_payment_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; + + /// Returns, if possible, the current investment amount (in pool currency) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed investment from pool + /// currency into tranche tokens. + fn investment( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Updates the current redemption amount (in tranche tokens) of who into + /// the investment class to amount. + /// Meaning: if amount < previous redemption, then the redemption + /// will be reduced, and increased in the opposite case. + /// + /// NOTE: Redemptions are bound by the processed investment amount. + fn update_redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Checks whether a currency is accepted as a payout for the given + /// investment. + fn accepted_payout_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; + + /// Returns, if possible, the current redemption amount (in tranche tokens) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed redemption from tranche + /// tokens into pool currency. + fn redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; +} + +/// A trait which allows to collect existing investments and redemptions. +pub trait InvestmentCollector { + type Error: Debug; + type InvestmentId; + type Result: Debug; + + /// Collect the results of a user's invest orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. + fn collect_investment( + who: AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Collect the results of a users redeem orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. + fn collect_redemption( + who: AccountId, + investment_id: Self::InvestmentId, + ) -> Result; +} + +/// A trait, when implemented must take care of +/// collecting orders (invest & redeem) for a given investment class. +/// When being asked it must return the current orders and +/// when being singled about a fulfillment, it must act accordingly. +pub trait OrderManager { + type Error; + type InvestmentId; + type Orders; + type Fulfillment; + + /// When called the manager return the current + /// invest orders for the given investment class. + fn invest_orders(asset_id: Self::InvestmentId) -> Self::Orders; + + /// When called the manager return the current + /// redeem orders for the given investment class. + fn redeem_orders(asset_id: Self::InvestmentId) -> Self::Orders; + + /// When called the manager return the current + /// invest orders for the given investment class. + /// Callers of this method can expect that the returned + /// orders equal the returned orders from `invest_orders`. + /// + /// **NOTE:** Once this is called, the OrderManager is expected + /// to start a new round of orders and return an error if this + /// method is to be called again before `invest_fulfillment` is + /// called. + fn process_invest_orders(asset_id: Self::InvestmentId) -> Result; + + /// When called the manager return the current + /// invest orders for the given investment class. + /// Callers of this method can expect that the returned + /// orders equal the returned orders from `redeem_orders`. + /// + /// **NOTE:** Once this is called, the OrderManager is expected + /// to start a new round of orders and return an error if this + /// method is to be called again before `redeem_fulfillment` is + /// called. + fn process_redeem_orders(asset_id: Self::InvestmentId) -> Result; + + /// 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>; + + /// 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>; +} + +/// A trait who's implementer provides means of accounting +/// for investments of a generic kind. +pub trait InvestmentAccountant { + type Error; + type InvestmentId; + type InvestmentInfo: InvestmentProperties; + type Amount; + + /// Information about an asset. Must allow to derive + /// owner, payment and denomination currency + fn info(id: Self::InvestmentId) -> Result; + + /// Return the balance of a given user for the given investmnet + fn balance(id: Self::InvestmentId, who: &AccountId) -> Self::Amount; + + /// Transfer a given investment from source, to destination + fn transfer( + id: Self::InvestmentId, + source: &AccountId, + dest: &AccountId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Increases the existance of + fn deposit( + buyer: &AccountId, + id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Reduce the existance of an asset + fn withdraw( + seller: &AccountId, + id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; +} + +/// A trait that allows to retrieve information +/// about an investment class. +pub trait InvestmentProperties { + /// The overarching Currency that payments + /// for this class are made in + type Currency; + /// Who the investment class can be identified + type Id; + + /// Returns the owner of the investment class + fn owner(&self) -> AccountId; + + /// Returns the id of the investment class + fn id(&self) -> Self::Id; + + /// Returns the currency in which the investment class + /// can be bought. + fn payment_currency(&self) -> Self::Currency; + + /// Returns the account a payment for the investment class + /// must be made to. + /// + /// Defaults to owner. + fn payment_account(&self) -> AccountId { + self.owner() + } +} + +impl> InvestmentProperties for &T { + type Currency = T::Currency; + type Id = T::Id; + + fn owner(&self) -> AccountId { + (*self).owner() + } + + fn id(&self) -> Self::Id { + (*self).id() + } + + fn payment_currency(&self) -> Self::Currency { + (*self).payment_currency() + } + + fn payment_account(&self) -> AccountId { + (*self).payment_account() + } +} + +/// Trait to handle Investment Portfolios for accounts +pub trait InvestmentsPortfolio { + type InvestmentId; + type CurrencyId; + type Balance; + type Error; + type AccountInvestmentPortfolio; + + /// Get the payment currency for an investment. + fn get_investment_currency_id( + investment_id: Self::InvestmentId, + ) -> Result; + + /// Get the investments and associated payment currencies and balances for + /// an account. + fn get_account_investments_currency( + who: &Account, + ) -> Result; +} + +/// Trait to handle investments in (presumably) foreign currencies, i.e., other +/// currencies than the pool currency. +/// +/// NOTE: Has many similarities with the [Investment] trait. +pub trait ForeignInvestment { + type Amount; + type CurrencyId; + type Error: Debug; + type InvestmentId; + type CollectInvestResult; + + /// Initiates the increment of a foreign investment amount in + /// `return_currency` of who into the investment class `pool_currency` to + /// amount. + /// + /// NOTE: In general, we can assume that the return and pool currencies + /// mismatch and that swapping one into the other happens asynchronously. In + /// that case, the finalization of updating the investment needs to be + /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. + fn increase_foreign_investment( + who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + ) -> Result<(), Self::Error>; + + /// Initiates the decrement of a foreign investment amount in + /// `return_currency` of who into the investment class `pool_currency` to + /// amount. + /// + /// NOTE: In general, we can assume that the return and pool currencies + /// mismatch and that swapping one into the other happens asynchronously. In + /// that case, the finalization of updating the investment needs to be + /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. + fn decrease_foreign_investment( + who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + ) -> Result<(), Self::Error>; + + /// Initiates the increment of a foreign redemption amount from + /// `pool_currency` of who into `return_currency` to amount. + /// + /// NOTE: The incrementing redemption amount is bound by the processed + /// investment amount. + fn increase_foreign_redemption( + who: &AccountId, + // TODO: Check if we do not require them if can be derived in CollectRedeemOrder + // return_currency: Self::CurrencyId, + // pool_currency: Self::CurrencyId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result<(), Self::Error>; + + /// Initiates the decrement of a foreign redemption amount from + /// `pool_currency` of who into `return_currency` to amount. + /// + /// NOTE: The decrementing redemption amount is bound by the previously + /// incremented redemption amount. + fn decrease_foreign_redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + amount: Self::Amount, + ) -> Result; + + /// Collect the results of a user's foreign invest orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. + fn collect_foreign_investment( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Collect the results of a user's foreign redeem orders for the given + /// investment. If any amounts are not fulfilled they are directly + /// appended to the next active order for this investment. + /// + /// NOTE: The currency of the collected amount will be `pool_currency` + /// whereas the user eventually wants to receive it in `return_currency`. + fn collect_foreign_redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, + ) -> Result<(), Self::Error>; + + /// Returns, if possible, the current investment amount (in pool currency) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed investment from pool + /// currency into tranche tokens. + fn investment( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Returns, if possible, the current redemption amount (in tranche tokens) + /// of who into the given investment class. + /// + /// NOTE: Does NOT include any (partially) processed redemption from tranche + /// tokens into pool currency. + fn redemption( + who: &AccountId, + investment_id: Self::InvestmentId, + ) -> Result; + + /// Checks whether a currency can be used for buying the given investment. + fn accepted_payment_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; + + /// Checks whether a currency is accepted as a payout for the given + /// investment. + fn accepted_payout_currency( + investment_id: Self::InvestmentId, + currency: Self::CurrencyId, + ) -> bool; +} diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 605cf0d4a9..1966e7be1d 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -44,6 +44,8 @@ pub mod data; pub mod ethereum; /// Traits related to interest rates. pub mod interest; +/// Traits related to investments. +pub mod investments; /// Traits related to rewards. pub mod rewards; @@ -368,247 +370,6 @@ impl PreConditions for Never { } } -/// A trait for converting from a PoolId and a TranchId -/// into a given Self::Currency -pub trait TrancheCurrency { - fn generate(pool_id: PoolId, tranche_id: TrancheId) -> Self; - - fn of_pool(&self) -> PoolId; - - fn of_tranche(&self) -> TrancheId; -} - -/// A trait, when implemented allows to invest into -/// investment classes -pub trait Investment { - type Amount; - type CurrencyId; - type Error: Debug; - type InvestmentId; - - /// Updates the current investment amount of who into the - /// investment class to amount. - /// Meaning: if amount < previous investment, then investment - /// will be reduced, and increases in the opposite case. - fn update_investment( - who: &AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Checks whether a currency can be used for buying the given investment. - fn accepted_payment_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool; - - /// Returns, if possible, the current investment amount (in pool currency) - /// of who into the given investment class. - /// - /// NOTE: Does NOT include any (partially) processed investment from pool - /// currency into tranche tokens. - fn investment( - who: &AccountId, - investment_id: Self::InvestmentId, - ) -> Result; - - /// Updates the current redemption amount (in tranche tokens) of who into - /// the investment class to amount. - /// Meaning: if amount < previous redemption, then the redemption - /// will be reduced, and increased in the opposite case. - /// - /// NOTE: Redemptions are bound by the processed investment amount. - fn update_redemption( - who: &AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Checks whether a currency is accepted as a payout for the given - /// investment. - fn accepted_payout_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool; - - /// Returns, if possible, the current redemption amount (in tranche tokens) - /// of who into the given investment class. - /// - /// NOTE: Does NOT include any (partially) processed redemption from tranche - /// tokens into pool currency. - fn redemption( - who: &AccountId, - investment_id: Self::InvestmentId, - ) -> Result; -} - -/// A trait which allows to collect existing investments and redemptions. -pub trait InvestmentCollector { - type Error: Debug; - type InvestmentId; - type Result: Debug; - - /// Collect the results of a user's invest orders for the given - /// investment. If any amounts are not fulfilled they are directly - /// appended to the next active order for this investment. - fn collect_investment( - who: AccountId, - investment_id: Self::InvestmentId, - ) -> Result; - - /// Collect the results of a users redeem orders for the given - /// investment. If any amounts are not fulfilled they are directly - /// appended to the next active order for this investment. - fn collect_redemption( - who: AccountId, - investment_id: Self::InvestmentId, - ) -> Result; -} - -/// A trait, when implemented must take care of -/// collecting orders (invest & redeem) for a given investment class. -/// When being asked it must return the current orders and -/// when being singled about a fulfillment, it must act accordingly. -pub trait OrderManager { - type Error; - type InvestmentId; - type Orders; - type Fulfillment; - - /// When called the manager return the current - /// invest orders for the given investment class. - fn invest_orders(asset_id: Self::InvestmentId) -> Self::Orders; - - /// When called the manager return the current - /// redeem orders for the given investment class. - fn redeem_orders(asset_id: Self::InvestmentId) -> Self::Orders; - - /// When called the manager return the current - /// invest orders for the given investment class. - /// Callers of this method can expect that the returned - /// orders equal the returned orders from `invest_orders`. - /// - /// **NOTE:** Once this is called, the OrderManager is expected - /// to start a new round of orders and return an error if this - /// method is to be called again before `invest_fulfillment` is - /// called. - fn process_invest_orders(asset_id: Self::InvestmentId) -> Result; - - /// When called the manager return the current - /// invest orders for the given investment class. - /// Callers of this method can expect that the returned - /// orders equal the returned orders from `redeem_orders`. - /// - /// **NOTE:** Once this is called, the OrderManager is expected - /// to start a new round of orders and return an error if this - /// method is to be called again before `redeem_fulfillment` is - /// called. - fn process_redeem_orders(asset_id: Self::InvestmentId) -> Result; - - /// 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>; - - /// 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>; -} - -/// A trait who's implementer provides means of accounting -/// for investments of a generic kind. -pub trait InvestmentAccountant { - type Error; - type InvestmentId; - type InvestmentInfo: InvestmentProperties; - type Amount; - - /// Information about an asset. Must allow to derive - /// owner, payment and denomination currency - fn info(id: Self::InvestmentId) -> Result; - - /// Return the balance of a given user for the given investmnet - fn balance(id: Self::InvestmentId, who: &AccountId) -> Self::Amount; - - /// Transfer a given investment from source, to destination - fn transfer( - id: Self::InvestmentId, - source: &AccountId, - dest: &AccountId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Increases the existance of - fn deposit( - buyer: &AccountId, - id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Reduce the existance of an asset - fn withdraw( - seller: &AccountId, - id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; -} - -/// A trait that allows to retrieve information -/// about an investment class. -pub trait InvestmentProperties { - /// The overarching Currency that payments - /// for this class are made in - type Currency; - /// Who the investment class can be identified - type Id; - - /// Returns the owner of the investment class - fn owner(&self) -> AccountId; - - /// Returns the id of the investment class - fn id(&self) -> Self::Id; - - /// Returns the currency in which the investment class - /// can be bought. - fn payment_currency(&self) -> Self::Currency; - - /// Returns the account a payment for the investment class - /// must be made to. - /// - /// Defaults to owner. - fn payment_account(&self) -> AccountId { - self.owner() - } -} - -impl> InvestmentProperties for &T { - type Currency = T::Currency; - type Id = T::Id; - - fn owner(&self) -> AccountId { - (*self).owner() - } - - fn id(&self) -> Self::Id { - (*self).id() - } - - fn payment_currency(&self) -> Self::Currency { - (*self).payment_currency() - } - - fn payment_account(&self) -> AccountId { - (*self).payment_account() - } -} - pub mod fees { use codec::FullCodec; use frame_support::{dispatch::DispatchResult, traits::tokens::Balance}; @@ -702,7 +463,7 @@ pub trait TokenSwaps { type Balance; type OrderId; /// Swap tokens buying a `buy_amount` of `currency_in` using the - /// `currency_out` tokens. The implementator of this method should know + /// `currency_out` tokens. The implementer of this method should know /// the current market rate between those two currencies. /// `sell_price_limit` defines the lowest price acceptable for /// `currency_in` currency when buying with `currency_out`. This @@ -738,151 +499,7 @@ pub trait TokenSwaps { fn is_active(order: Self::OrderId) -> bool; } -/// Trait to handle Investment Portfolios for accounts -pub trait InvestmentsPortfolio { - type InvestmentId; - type CurrencyId; - type Balance; - type Error; - type AccountInvestmentPortfolio; - - /// Get the payment currency for an investment. - fn get_investment_currency_id( - investment_id: Self::InvestmentId, - ) -> Result; - - /// Get the investments and associated payment currencies and balances for - /// an account. - fn get_account_investments_currency( - who: &Account, - ) -> Result; -} - -/// Trait to handle investments in (presumably) foreign currencies, i.e., other -/// currencies than the pool currency. -/// -/// NOTE: Has many similarities with the [Investment] trait. -pub trait ForeignInvestment { - type Amount; - type CurrencyId; - type Error: Debug; - type InvestmentId; - - /// Initiates the increment of a foreign investment amount in - /// `return_currency` of who into the investment class `pool_currency` to - /// amount. - /// - /// NOTE: In general, we can assume that the return and pool currencies - /// mismatch and that swapping one into the other happens asynchronously. In - /// that case, the finalization of updating the investment needs to be - /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. - fn increase_foreign_investment( - who: &AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - return_currency: Self::CurrencyId, - pool_currency: Self::CurrencyId, - ) -> Result<(), Self::Error>; - - /// Initiates the decrement of a foreign investment amount in - /// `return_currency` of who into the investment class `pool_currency` to - /// amount. - /// - /// NOTE: In general, we can assume that the return and pool currencies - /// mismatch and that swapping one into the other happens asynchronously. In - /// that case, the finalization of updating the investment needs to be - /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. - fn decrease_foreign_investment( - who: &AccountId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - return_currency: Self::CurrencyId, - pool_currency: Self::CurrencyId, - ) -> Result<(), Self::Error>; - - /// Initiates the increment of a foreign redemption amount from - /// `pool_currency` of who into `return_currency` to amount. - /// - /// NOTE: The incrementing redemption amount is bound by the processed - /// investment amount. - fn increase_foreign_redemption( - who: &AccountId, - // TODO: Check if we do not require them if can be derived in CollectRedeemOrder - // return_currency: Self::CurrencyId, - // pool_currency: Self::CurrencyId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Initiates the decrement of a foreign redemption amount from - /// `pool_currency` of who into `return_currency` to amount. - /// - /// NOTE: The decrementing redemption amount is bound by the previously - /// incremented redemption amount. - fn decrease_foreign_redemption( - who: &AccountId, - // TODO: Check if we do not require them if can be derived in CollectRedeemOrder - // return_currency: Self::CurrencyId, - // pool_currency: Self::CurrencyId, - investment_id: Self::InvestmentId, - amount: Self::Amount, - ) -> Result<(), Self::Error>; - - /// Collect the results of a user's foreign invest orders for the given - /// investment. If any amounts are not fulfilled they are directly - /// appended to the next active order for this investment. - fn collect_foreign_investment( - who: &AccountId, - investment_id: Self::InvestmentId, - ) -> Result<(), Self::Error>; - - /// Collect the results of a user's foreign redeem orders for the given - /// investment. If any amounts are not fulfilled they are directly - /// appended to the next active order for this investment. - /// - /// NOTE: The currency of the collected amount will be `pool_currency` - /// whereas the user eventually wants to receive it in `return_currency`. - fn collect_foreign_redemption( - who: &AccountId, - investment_id: Self::InvestmentId, - return_currency: Self::CurrencyId, - pool_currency: Self::CurrencyId, - ) -> Result<(), Self::Error>; - - /// Returns, if possible, the current investment amount (in pool currency) - /// of who into the given investment class. - /// - /// NOTE: Does NOT include any (partially) processed investment from pool - /// currency into tranche tokens. - fn investment( - who: &AccountId, - investment_id: Self::InvestmentId, - ) -> Result; - - /// Returns, if possible, the current redemption amount (in tranche tokens) - /// of who into the given investment class. - /// - /// NOTE: Does NOT include any (partially) processed redemption from tranche - /// tokens into pool currency. - fn redemption( - who: &AccountId, - investment_id: Self::InvestmentId, - ) -> Result; - - /// Checks whether a currency can be used for buying the given investment. - fn accepted_payment_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool; - - /// Checks whether a currency is accepted as a payout for the given - /// investment. - fn accepted_payout_currency( - investment_id: Self::InvestmentId, - currency: Self::CurrencyId, - ) -> bool; -} - +// TODO: Docs pub trait StatusNotificationHook { /// The identifying type type Id; diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index cbcaaf8580..68ee34b87e 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -10,12 +10,16 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::InvestmentProperties; +use cfg_primitives::OrderId; +use cfg_traits::investments::InvestmentProperties; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; +use sp_runtime::traits::Zero; use sp_std::cmp::PartialEq; +use crate::orders::Order; + /// A representation of a investment identifier that can be converted to an /// account address #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] @@ -53,6 +57,122 @@ where } } +/// The outstanding collections for an account +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct InvestCollection { + /// This is the payout in the denomination currency + /// of an investment + /// * If investment: In payment currency + /// * If payout: In denomination currency + pub payout_investment_invest: Balance, + + /// This is the remaining investment in the payment currency + /// of an investment + /// * If investment: In payment currency + /// * If payout: In denomination currency + pub remaining_investment_invest: Balance, +} + +impl Default for InvestCollection { + fn default() -> Self { + InvestCollection { + payout_investment_invest: Zero::zero(), + remaining_investment_invest: Zero::zero(), + } + } +} + +impl InvestCollection { + /// Create a `InvestCollection` directly from an active invest order of + /// a user. + /// The field `remaining_investment_invest` is set to the + /// amount of the active invest order of the user and will + /// be subtracted from upon given fulfillment's + pub fn from_order(order: &Order) -> Self { + InvestCollection { + payout_investment_invest: Zero::zero(), + remaining_investment_invest: order.amount(), + } + } +} + +/// The outstanding collections for an account +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct RedeemCollection { + /// This is the payout in the payment currency + /// of an investment + /// * If redemption: In denomination currency + /// * If payout: In payment currency + pub payout_investment_redeem: Balance, + + /// This is the remaining redemption in the denomination currency + /// of an investment + /// * If redemption: In denomination currency + /// * If payout: In payment currency + pub remaining_investment_redeem: Balance, +} + +impl Default for RedeemCollection { + fn default() -> Self { + RedeemCollection { + payout_investment_redeem: Zero::zero(), + remaining_investment_redeem: Zero::zero(), + } + } +} + +impl RedeemCollection { + /// Create a `RedeemCollection` directly from an active redeem order of + /// a user. + /// The field `remaining_investment_redeem` is set to the + /// amount of the active redeem order of the user and will + /// be subtracted from upon given fulfillment's + pub fn from_order(order: &Order) -> Self { + RedeemCollection { + payout_investment_redeem: Zero::zero(), + remaining_investment_redeem: order.amount(), + } + } +} + +/// The collected investment/redemption amount for an account +#[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct CollectedAmount { + /// The amount which was was collected + /// * If investment: Tranche tokens + /// * If redemption: Payment currency + pub amount_collected: Balance, + + /// The amount which invested and converted during processing based on the + /// fulfillment price(s) + /// * If investment: Payment currency + /// * If redemption: Tranche tokens + pub amount_payment: Balance, +} + +// /// The collected investment for an account +// #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, +// TypeInfo)] pub struct CollectedInvestment { +// /// The amount of tranche tokens which was was collected +// pub amount_collected: Balance, + +// /// The amount of payment currency which invested and converted into tranche +// /// tokens during processing based on the fulfillment price(s) +// pub amount_payment: Balance, +// } + +// /// The collected redemption for an account +// #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, +// TypeInfo)] pub struct CollectedRedemption { +// /// The amount of payment currency which was was collected +// pub amount_collected: Balance, + +// /// The tranche tokens which which was held as an investment and converted +// /// into payment currency during processing based on the fulfillment +// /// price(s) +// pub amount_payment: Balance, +// } + /// A representation of an investment identifier and the corresponding owner. /// /// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. @@ -66,18 +186,38 @@ pub struct ForeignInvestmentInfo { /// A representation of an executed decreased investment or redemption. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ExecutedDecrease { +pub struct ExecutedDecrease { + pub return_currency: Currency, pub amount_decreased: Balance, pub amount_remaining: Balance, } -/// A representation of an executed collected investment or redemption. +/// A representation of an executed collected investment. +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] + +pub struct ExecutedCollectInvest { + /// The amount that was actually collected + pub amount_currency_payout: Balance, + /// The amount of tranche tokens received for the investment made + pub amount_tranche_tokens_payout: Balance, + // TODO: Processed or unprocessed? + /// The remaining, unprocessed investment amount which the investor + /// still has locked to invest at a later epoch execution + pub amount_remaining: Balance, +} + +/// A representation of an executed collected redemption. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ExecutedCollect { - // TODO: Check if necessary or can be used better - pub currency: Option, +pub struct ExecutedCollectRedeem { + /// The return currency in which the payout takes place + pub currency: Currency, + /// The amount of `currency` being paid out to the investor pub amount_currency_payout: Balance, + /// How many tranche tokens were actually redeemed pub amount_tranche_tokens_payout: Balance, + // TODO: Processed or unprocessed? + /// The remaining amount of tranche tokens the investor still has locked + /// to redeem at a later epoch execution pub amount_remaining: Balance, } diff --git a/libs/types/src/tokens.rs b/libs/types/src/tokens.rs index 8b29866350..68f9f7adbd 100644 --- a/libs/types/src/tokens.rs +++ b/libs/types/src/tokens.rs @@ -13,7 +13,7 @@ use core::marker::PhantomData; use cfg_primitives::types::{PoolId, TrancheId}; -use cfg_traits::TrancheCurrency as TrancheCurrencyT; +use cfg_traits::investments::TrancheCurrency as TrancheCurrencyT; use codec::{Decode, Encode, MaxEncodedLen}; pub use orml_asset_registry::AssetMetadata; use scale_info::TypeInfo; @@ -21,7 +21,7 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_runtime::{traits::Get, DispatchError, TokenError}; -use crate::{xcm::XcmMetadata, EVMChainId}; +use crate::{domain_address::DomainAddress, xcm::XcmMetadata, EVMChainId}; /// The type for all Currency ids that our chains handles. /// Foreign assets gather all the tokens that are native to other chains, such @@ -308,6 +308,14 @@ pub enum ConnectorsWrappedToken { }, } +impl Into for ConnectorsWrappedToken { + fn into(self) -> DomainAddress { + match self { + Self::EVM { chain_id, address } => DomainAddress::EVM(chain_id, address), + } + } +} + pub mod before { use cfg_primitives::{PoolId, TrancheId}; use codec::{Decode, Encode, MaxEncodedLen}; diff --git a/pallets/connectors/src/hooks.rs b/pallets/connectors/src/hooks.rs new file mode 100644 index 0000000000..0778848d36 --- /dev/null +++ b/pallets/connectors/src/hooks.rs @@ -0,0 +1,107 @@ +// 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 cfg_traits::{connectors::OutboundQueue, investments::TrancheCurrency, StatusNotificationHook}; +use cfg_types::{ + domain_address::DomainAddress, + investments::{ExecutedDecrease, ForeignInvestmentInfo}, +}; +use frame_support::{traits::fungibles::Mutate, transactional}; +use sp_runtime::{DispatchError, DispatchResult}; +use sp_std::marker::PhantomData; + +use crate::{pallet::Config, Message, MessageOf, Pallet}; + +// TODO: Docs +pub struct DecreaseInvestOrderHook(PhantomData); + +// TODO: Docs + +pub struct CollectRedeemHook(PhantomData); + +impl StatusNotificationHook for DecreaseInvestOrderHook +where + ::AccountId: Into<[u8; 32]>, +{ + type Error = DispatchError; + type Id = ForeignInvestmentInfo; + type Status = ExecutedDecrease; + + #[transactional] + fn notify_status_change( + id: ForeignInvestmentInfo, + status: ExecutedDecrease, + ) -> DispatchResult { + let ForeignInvestmentInfo { + id: investment_id, + owner: investor, + } = id; + let currency = Pallet::::try_get_general_index(status.return_currency)?; + let wrapped_token = Pallet::::try_get_wrapped_token(&status.return_currency)?; + let domain_address: DomainAddress = wrapped_token.into(); + + T::Tokens::burn_from(status.return_currency, &investor, status.amount_decreased)?; + + let message: MessageOf = Message::ExecutedDecreaseInvestOrder { + pool_id: investment_id.of_pool(), + tranche_id: investment_id.of_tranche(), + investor: investor.clone().into(), + currency, + currency_payout: status.amount_decreased, + remaining_invest_order: status.amount_remaining, + }; + + T::OutboundQueue::submit(investor, domain_address.into(), message)?; + + Ok(()) + } +} + +impl StatusNotificationHook for CollectRedeemHook +where + ::AccountId: Into<[u8; 32]>, +{ + type Error = DispatchError; + type Id = ForeignInvestmentInfo; + type Status = cfg_types::investments::ExecutedCollectRedeem; + + #[transactional] + fn notify_status_change( + id: ForeignInvestmentInfo, + status: cfg_types::investments::ExecutedCollectRedeem, + ) -> DispatchResult { + let ForeignInvestmentInfo { + id: investment_id, + owner: investor, + } = id; + let currency = Pallet::::try_get_general_index(status.currency)?; + let wrapped_token = Pallet::::try_get_wrapped_token(&status.currency)?; + let domain_address: DomainAddress = wrapped_token.into(); + + T::Tokens::burn_from(status.currency, &investor, status.amount_currency_payout)?; + + let message: MessageOf = Message::ExecutedCollectInvest { + pool_id: investment_id.of_pool(), + tranche_id: investment_id.of_tranche(), + investor: investor.clone().into(), + currency, + currency_payout: status.amount_currency_payout, + tranche_tokens_payout: status.amount_tranche_tokens_payout, + remaining_invest_order: status.amount_remaining, + }; + + T::OutboundQueue::submit(investor, domain_address.into(), message)?; + + Ok(()) + } +} diff --git a/pallets/connectors/src/inbound.rs b/pallets/connectors/src/inbound.rs index af240de160..08710751bd 100644 --- a/pallets/connectors/src/inbound.rs +++ b/pallets/connectors/src/inbound.rs @@ -11,9 +11,12 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Permissions, PoolInspect}; +use cfg_traits::{ + connectors::OutboundQueue, investments::ForeignInvestment, Permissions, PoolInspect, +}; use cfg_types::{ domain_address::{Domain, DomainAddress}, + investments::ExecutedCollectInvest, permissions::{PermissionScope, PoolRole, Role}, }; use frame_support::{ @@ -25,7 +28,7 @@ use sp_runtime::{ DispatchResult, }; -use crate::{pallet::Error, Config, GeneralCurrencyIndexOf, Pallet}; +use crate::{pallet::Error, Config, GeneralCurrencyIndexOf, Message, MessageOf, Pallet}; impl Pallet { /// Executes a transfer from another domain exclusively for @@ -85,6 +88,9 @@ impl Pallet { /// /// Directly mints the additional investment amount into the investor /// account. + /// + /// If the provided currency does not match the pool currency, a token swap + /// is initiated. pub fn handle_increase_invest_order( pool_id: T::PoolId, tranche_id: T::TrancheId, @@ -111,12 +117,15 @@ impl Pallet { Ok(()) } - /// Decreases an existing investment order of the investor. + /// Initiates the decrement of an existing investment order of the investor. + /// + /// On success, the unprocessed investment amount is decremented and a swap + /// back into the provided return currency initiated. /// - /// Initiates a return `ExecutedDecreaseInvestOrder` message to refund the - /// decreased amount on the source domain. The dispatch of this message is - /// delayed until the execution of the investment, e.g. at least until the - /// next epoch transition. + /// The finalization of this call (fulfillment of the swap) is assumed to be + /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` + /// which burns the corresponding amount in return currency and dispatches + /// `ExecutedDecreaseInvestOrder`. pub fn handle_decrease_invest_order( pool_id: T::PoolId, tranche_id: T::TrancheId, @@ -137,23 +146,12 @@ impl Pallet { pool_currency, )?; - // TODO: Handle response `ExecutedDecreaseInvestOrder` message to - // source destination which should refund the decreased amount. This includes - // burning it from the investor account. - // - // NOTES: - // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 - // * Should be handled by `pallet-foreign-investment` - // * Requires notification of `currency_payout` and `remaining_invest_order` - // balances - Ok(()) } /// Increases an existing redemption order of the investor. - // FIXME: This does not make sense? Once the redemption is processed and collected, the foreign - // investment swaps it into return currency into the investor, not the domainlocator. - /// Transfers the decreased redemption amount from the holdings of the + /// + /// Transfers the increase redemption amount from the holdings of the /// `DomainLocator` account of origination domain of this message into the /// investor account. /// @@ -167,79 +165,131 @@ impl Pallet { sending_domain: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + + // Transfer tranche tokens from `DomainLocator` account of + // origination domain + // TODO(@review): Should this rather be pat of `increase_foreign_redemption`? + T::Tokens::transfer( + invest_id.clone().into(), + &Domain::convert(sending_domain.domain()), + &investor, + amount, + false, + )?; + T::ForeignInvestment::increase_foreign_redemption(&investor, invest_id, amount)?; Ok(()) - - // TODO: Handle transfer in hook or drop entirely - // // Transfer tranche tokens from `DomainLocator` account of - // origination domain T::Tokens::transfer( - // invest_id.clone().into(), - // &Domain::convert(sending_domain.domain()), - // &investor, - // amount, - // false, - // )?; } /// Decreases an existing redemption order of the investor. /// /// Initiates a return `ExecutedDecreaseRedemption` message to refund the - /// decreased amount on the source domain. The dispatch of this message is - /// delayed until the execution of the redemption, e.g. at least until the - /// next epoch transition. + /// decreased amount on the source domain. + /// + /// NOTE: In contrast to investments, redemption decrements happen + /// fully synchronously as they can only be called in between increasing a + /// redemption and its (full) processing. pub fn handle_decrease_redemption( pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, + investor_bytes: [u8; 32], currency_index: GeneralCurrencyIndexOf, amount: ::Balance, - _sending_domain: DomainAddress, + destination: Domain, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - T::ForeignInvestment::decrease_foreign_redemption(&investor, invest_id, amount)?; + // TODO(@review): This is exactly `amount` as we can only decrement up to the + // unprocessed redemption + let tranche_tokens_payout = T::ForeignInvestment::decrease_foreign_redemption( + &investor, + invest_id.clone(), + amount, + )?; - Ok(()) + T::Tokens::transfer( + invest_id.into(), + &investor, + &Domain::convert(destination.clone()), + tranche_tokens_payout, + false, + )?; - // TODO: Handle response `ExecutedDecreaseRedemption` message to - // source destination which should refund the decreased amount. This - // includes transferring the amount from the investor to the domain - // locator account of the origination domain. - // - // NOTES: - // * Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1363 - // * Should be handled by `pallet-foreign-investment` - // * Requires notification of `tranche_tokens_payout` and - // `remaining_redeem_order` balances + let message: MessageOf = Message::ExecutedDecreaseRedeemOrder { + pool_id, + tranche_id, + investor: investor_bytes, + currency: currency_index.index, + tranche_tokens_payout: tranche_tokens_payout, + }; + + T::OutboundQueue::submit(investor, destination, message)?; + + Ok(()) } /// Collect the results of a user's invest orders for the given investment /// id. If any amounts are not fulfilled, they are directly appended to the /// next active order for this investment. + /// + /// Transfers collected amount from investor's sovereign account to the + /// sending domain locator. + /// + /// NOTE: In contrast to collecting a redemption, investments can be + /// collected entirely synchronously as it does not involve swapping. It + /// simply transfers the tranche tokens from the pool to the sovereign + /// investor account on the local domain. pub fn handle_collect_investment( pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, + investor_bytes: [u8; 32], + currency_index: GeneralCurrencyIndexOf, + destination: Domain, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - T::ForeignInvestment::collect_foreign_investment(&investor, invest_id)?; + let ExecutedCollectInvest:: { + amount_currency_payout, + amount_tranche_tokens_payout, + amount_remaining, + } = T::ForeignInvestment::collect_foreign_investment(&investor, invest_id.clone())?; - // T::ForeignInvestment::collect_foreign_investment(investor, invest_id, ) + T::Tokens::transfer( + invest_id.into(), + &investor, + &Domain::convert(destination.clone()), + amount_tranche_tokens_payout, + false, + )?; - // TODO: Handle response `ExecutedCollectInvest` message to - // source destination. - // - // Requires notification of `currency_payout`, `tranche_tokens_payout` and - // `remaining_invest_order` balances as well as the payout currency id, which - // needs to be mapped to its general index. + let message: MessageOf = Message::ExecutedCollectInvest { + pool_id, + tranche_id, + investor: investor_bytes, + currency: currency_index.index, + currency_payout: amount_currency_payout, + tranche_tokens_payout: amount_tranche_tokens_payout, + remaining_invest_order: amount_remaining, + }; + + T::OutboundQueue::submit(investor, destination, message)?; Ok(()) } /// Collect the results of a user's redeem orders for the given investment - /// id. If any amounts are not fulfilled, they are directly appended to the - /// next active order for this investment. + /// id in the pool currency. If any amounts are not fulfilled, they are + /// directly appended to the next active order for this investment. + /// + /// On success, a swap will be initiated to exchange the (partially) + /// collected amount in pool currency into the desired return currency. + /// + /// The termination of this call (fulfillment of the swap) is assumed to be + /// asynchronous and handled by the `CollectRedeemHook`. It burns the return + /// currency amount and dispatches `Message::ExecutedCollectRedeem` to the + /// destination domain. pub fn handle_collect_redemption( pool_id: T::PoolId, tranche_id: T::TrancheId, @@ -258,16 +308,6 @@ impl Pallet { pool_currency, )?; - // TODO: Handle response `ExecutedCollectRedeem` message to - // source destination. - // - // Requires notification of `currency_payout`, `tranche_tokens_payout` and - // `remaining_redeem_order` balances as well as the payout currency id, which - // needs to be mapped to its general index. - Ok(()) } - - // TODO: At some point, some token transfer needs to happen for redemptions and - // decrease investment } diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 9f100458d9..1c212567cc 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -16,6 +16,7 @@ use core::convert::TryFrom; use cfg_traits::connectors::{InboundQueue, OutboundQueue}; use cfg_types::{ domain_address::{Domain, DomainAddress}, + investments::ExecutedCollectInvest, tokens::GeneralCurrencyIndex, }; use cfg_utils::vec_to_fixed_array; @@ -52,6 +53,7 @@ pub use routers::*; mod contract; pub use contract::*; +pub mod hooks; mod inbound; /// The Parachains that Centrifuge Connectors support. @@ -83,8 +85,8 @@ pub type GeneralCurrencyIndexOf = pub mod pallet { use cfg_primitives::Moment; use cfg_traits::{ - CurrencyInspect, ForeignInvestment, Permissions, PoolInspect, TrancheCurrency, - TrancheTokenPrice, + investments::{ForeignInvestment, TrancheCurrency}, + CurrencyInspect, Permissions, PoolInspect, TrancheTokenPrice, }; use cfg_types::{ permissions::{PermissionScope, PoolRole, Role}, @@ -93,7 +95,7 @@ pub mod pallet { use codec::HasCompact; use frame_support::{pallet_prelude::*, traits::UnixTime}; use frame_system::pallet_prelude::*; - use sp_runtime::traits::Zero; + use sp_runtime::{traits::Zero, DispatchError}; use xcm::latest::MultiLocation; use super::*; @@ -196,6 +198,7 @@ pub mod pallet { CurrencyId = CurrencyIdOf, Error = DispatchError, InvestmentId = ::TrancheCurrency, + CollectInvestResult = ExecutedCollectInvest, >; /// The source of truth for the transferability of assets via @@ -890,15 +893,24 @@ pub mod pallet { pool_id, tranche_id, investor.into(), + investor, currency.into(), amount, - sender, + sender.into(), ), Message::CollectInvest { pool_id, tranche_id, investor, - } => Self::handle_collect_investment(pool_id, tranche_id, investor.into()), + currency, + } => Self::handle_collect_investment( + pool_id, + tranche_id, + investor.into(), + investor, + currency.into(), + sender.into(), + ), Message::CollectRedeem { pool_id, tranche_id, diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 9669b0863b..64088b0fea 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -185,6 +185,7 @@ where pool_id: PoolId, tranche_id: TrancheId, investor: Address, + currency: u128, }, /// Collect the proceeds for the specified pair of pool and /// tranche token. @@ -240,9 +241,6 @@ where /// original `DecreaseRedeemOrder` message, i.e., the amount by which /// the redeem order was actually decreased by. tranche_tokens_payout: Balance, - /// The remaining amount of tranche tokens the investor still has locked - /// to redeem at a later epoch execution - remaining_redeem_order: Balance, }, /// The message sent back to the domain from which a `CollectInvest` message /// has been received, which will ensure the `investor` gets the payout @@ -264,7 +262,6 @@ where tranche_tokens_payout: Balance, /// The remaining amount of `currency` the investor still has locked to /// invest at a later epoch execution - // TODO: Should be MORE than Investment::investment(who, investment_id) remaining_invest_order: Balance, }, /// The message sent back to the domain from which a `CollectRedeem` message @@ -495,9 +492,15 @@ impl< pool_id, tranche_id, investor, + currency, } => encoded_message( self.call_type(), - vec![encode_be(pool_id), tranche_id.encode(), investor.to_vec()], + vec![ + encode_be(pool_id), + tranche_id.encode(), + investor.to_vec(), + encode_be(currency), + ], ), Message::CollectRedeem { pool_id, @@ -537,7 +540,6 @@ impl< investor, currency, tranche_tokens_payout, - remaining_redeem_order, } => encoded_message( self.call_type(), vec![ @@ -546,7 +548,6 @@ impl< investor.to_vec(), encode_be(currency), encode_be(tranche_tokens_payout), - encode_be(remaining_redeem_order), ], ), Message::ExecutedCollectInvest { @@ -673,6 +674,7 @@ impl< pool_id: decode_be_bytes::<8, _, _>(input)?, tranche_id: decode::<16, _, _>(input)?, investor: decode::<32, _, _>(input)?, + currency: decode_be_bytes::<8, _, _>(input)?, }), 14 => Ok(Self::CollectRedeem { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -694,7 +696,6 @@ impl< investor: decode::<32, _, _>(input)?, currency: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, - remaining_redeem_order: decode_be_bytes::<16, _, _>(input)?, }), 17 => Ok(Self::ExecutedCollectInvest { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -1008,6 +1009,7 @@ mod tests { pool_id: 1, tranche_id: default_tranche_id(), investor: default_address_32(), + currency: TOKEN_ID, }, "0d0000000000000001811acd5b3f17c06841c7e41e9e04cb1b4564564564564564564564564564564564564564564564564564564564564564", ) @@ -1050,7 +1052,6 @@ mod tests { investor: vec_to_fixed_array(default_address_20().to_vec()), currency: TOKEN_ID, tranche_tokens_payout: AMOUNT / 2, - remaining_redeem_order: AMOUNT * 2 }, "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e640669720000000000000000a56fa5b99019a5c8000000", ) diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml index 293ea147bd..d07585ef4d 100644 --- a/pallets/foreign-investments/Cargo.toml +++ b/pallets/foreign-investments/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Centrifuge "] description = "Pallet to enable investments and redemptions via a foreign interface" edition = "2021" license = "LGPL-3.0" -name = "pallet-foreign-investment" +name = "pallet-foreign-investments" repository = "https://github.com/centrifuge/centrifuge-chain" version = "1.0.0" diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index d0ac4f1b77..9d0a681000 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -12,12 +12,15 @@ // GNU General Public License for more details. use cfg_traits::{ - ForeignInvestment, Investment, InvestmentCollector, StatusNotificationHook, TokenSwaps, + investments::{ForeignInvestment, Investment, InvestmentCollector}, + StatusNotificationHook, TokenSwaps, +}; +use cfg_types::investments::{ + CollectedAmount, ExecutedCollectInvest, ExecutedCollectRedeem, ExecutedDecrease, }; -use cfg_types::investments::{ExecutedCollect, ExecutedDecrease, InvestmentInfo}; use frame_support::{traits::Get, transactional}; use sp_runtime::{ - traits::{EnsureAdd, Zero}, + traits::{EnsureAdd, EnsureAddAssign, Zero}, DispatchError, DispatchResult, }; @@ -26,8 +29,8 @@ use crate::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, Swap, TokenSwapReason, }, - Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, - RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, + CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, + InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, }; mod invest; @@ -61,6 +64,10 @@ impl StatusNotificationHook for Pallet { let post_state = pre_state.transition(RedeemTransition::FulfillSwapOrder(status))?; Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) + + // TODO: When RedeemState includes `SwapIntoReturnDone` without + // `ActiveSwapIntoReturnCurrency`, we must emit + // `ExecutedCollectRedeem`. } } } @@ -68,10 +75,12 @@ impl StatusNotificationHook for Pallet { impl ForeignInvestment for Pallet { type Amount = T::Balance; + type CollectInvestResult = ExecutedCollectInvest; type CurrencyId = T::CurrencyId; type Error = DispatchError; type InvestmentId = T::InvestmentId; + #[transactional] fn increase_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, @@ -91,6 +100,7 @@ impl ForeignInvestment for Pallet { Ok(()) } + #[transactional] fn decrease_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, @@ -110,6 +120,7 @@ impl ForeignInvestment for Pallet { Ok(()) } + #[transactional] fn increase_foreign_redemption( who: &T::AccountId, // return_currency: T::CurrencyId, @@ -125,54 +136,67 @@ impl ForeignInvestment for Pallet { Ok(()) } + #[transactional] fn decrease_foreign_redemption( who: &T::AccountId, - // return_currency: T::CurrencyId, - // pool_currency: T::CurrencyId, investment_id: T::InvestmentId, amount: T::Balance, - ) -> Result<(), DispatchError> { + ) -> Result { let pre_amount = T::Investment::redemption(who, investment_id.clone())?; let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = - pre_state.transition(RedeemTransition::DecreaseRedeemOrder(pre_amount - amount))?; - - Self::notify_executed_decrease_redeem(who, investment_id, amount)?; + let post_state = pre_state.transition(RedeemTransition::DecreaseRedeemOrder(amount))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; - Ok(()) + Ok(amount) } - // TODO: check if this should be transactional + #[transactional] fn collect_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(), DispatchError> { + ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is // independent of the current `InvestState` - let amount_collected = T::Investment::collect_investment(who.clone(), investment_id)?; - Self::notify_executed_collect_invest(who, investment_id, amount_collected) + let CollectedAmount:: { + amount_collected, + amount_payment, + } = T::Investment::collect_investment(who.clone(), investment_id)?; + let amount_currency_unprocessed = T::Investment::investment(who, investment_id)?; + + Ok(ExecutedCollectInvest { + amount_currency_payout: amount_payment, + amount_tranche_tokens_payout: amount_collected, + amount_remaining: amount_currency_unprocessed, + }) } + #[transactional] fn collect_foreign_redemption( who: &T::AccountId, investment_id: T::InvestmentId, return_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; + CollectedRedemption::::try_mutate(who, investment_id, |collected_redemption| { + collected_redemption + .amount_collected + .ensure_add_assign(collected.amount_collected)?; + collected_redemption + .amount_payment + .ensure_add_assign(collected.amount_payment)?; + + Ok::<(), DispatchError>(()) + })?; + // Transition state to initiate swap from pool to return currency let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = - pre_state.transition(RedeemTransition::Collect(return_currency, pool_currency))?; - - let amount_collected = T::Investment::collect_redemption(who.clone(), investment_id)?; - Self::notify_executed_collect_redeem( - who, - investment_id, - return_currency, - amount_collected, - )?; + let post_state = pre_state.transition(RedeemTransition::Collect(SwapOf:: { + amount: collected.amount_collected, + currency_in: return_currency, + currency_out: pool_currency, + }))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -229,10 +253,14 @@ impl Pallet { /// `RedemptionState` might require an update. /// /// 4. If the token swap handling resulted in a new `InvestState`, update - /// `InvestmentState` again. + /// `InvestmentState` again. Additionally, emit `ForeignInvestmentUpdate` or + /// `ForeignInvestmentCleared`. /// - /// 5. If the token swap handling resulted in a new `RedeemState`, - /// update `RedemptionState`. + /// 5. If the token swap handling resulted in a new `RedeemState`, update + /// `RedemptionState` again. If the corresponding new `InnerRedeemState` + /// includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency`, + /// remove the `SwapIntoReturnDone` part or kill it. Additionally, emit + /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 6. Update the investment. This also includes setting it to zero. We /// assume the impl of `::Investment` handles this case. @@ -248,81 +276,74 @@ impl Pallet { investment_id: T::InvestmentId, state: InvestState, ) -> DispatchResult { + // Do first round of updates and forward state, swap as well as invest amount match state.clone() { InvestState::NoState => { InvestmentState::::remove(who, investment_id); - Ok((None, Zero::zero())) + Ok((InvestState::NoState, None, Zero::zero())) }, InvestState::InvestmentOngoing { invest_amount } => { - InvestmentState::::insert(who, investment_id, state); + InvestmentState::::insert(who, investment_id, state.clone()); - Ok((None, invest_amount)) + Ok((state, None, invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrency { swap } | InvestState::ActiveSwapIntoReturnCurrency { swap } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { - InvestmentState::::insert(who, investment_id, state); - Ok((Some(swap), Zero::zero())) + InvestmentState::::insert(who, investment_id, state.clone()); + Ok((state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { - InvestmentState::::insert(who, investment_id, state); - Ok((Some(swap), invest_amount)) + InvestmentState::::insert(who, investment_id, state.clone()); + Ok((state, Some(swap), invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); - Ok((Some(swap), Zero::zero())) + Ok((new_state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); - Ok((Some(swap), invest_amount)) + Ok((new_state, Some(swap), invest_amount)) }, InvestState::SwapIntoReturnDone { done_swap } => { - Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount, done_swap.currency_in)?; InvestmentState::::remove(who, investment_id); - Ok((None, Zero::zero())) + Ok((InvestState::NoState, None, Zero::zero())) }, InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount)?; + Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount, done_swap.currency_in)?; let new_state = InvestState::InvestmentOngoing { invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); - Ok((None, invest_amount)) + Ok((new_state, None, invest_amount)) }, } - .map(|(maybe_swap, invest_amount)| { - let (maybe_invest_state, maybe_redeem_state) = - Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; - - // update invest and redeem states if necessary - InvestmentState::::mutate(who, investment_id, |current_invest_state| { - if maybe_invest_state != *current_invest_state { - *current_invest_state = maybe_invest_state; - } - // TODO: Maybe emit event of invest state transition from `state` to `current_invest_state` - }); + .map(|(invest_state, maybe_swap, invest_amount)| { + let (maybe_invest_state_prio, maybe_new_redeem_state) = Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; - RedemptionState::::mutate(who, investment_id, |current_redeem_state| { - if maybe_redeem_state != *current_redeem_state { - *current_redeem_state = maybe_redeem_state; - // TODO: Maybe emit event of redeem state transition from `current_redeem_state` to `new_state` - } - }); + // Dispatch transition event, post swap state has priority if it exists as it was the last transition + if let Some(invest_state_prio) = maybe_invest_state_prio { + Self::deposit_investment_event(who, investment_id, Some(invest_state_prio)); + } else { + Self::deposit_investment_event(who, investment_id, Some(invest_state)); + } + Self::deposit_redemption_event(who, investment_id, maybe_new_redeem_state); // Finally, update investment after all states have been updated T::Investment::update_investment(who, investment_id, invest_amount)?; @@ -351,10 +372,14 @@ impl Pallet { /// `RedemptionState` might require an update. /// /// 4. If the token swap handling resulted in a new `RedeemState`, update - /// `RedemptionState` again. + /// `RedemptionState` again. If the corresponding new `InnerRedeemState` + /// includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency`, + /// remove the `SwapIntoReturnDone` part or kill it. Additionally, emit + /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 5. If the token swap handling resulted in a new `InvestState`, - /// update `InvestmentState`. + /// update `InvestmentState`. Additionally, emit `ForeignInvestmentUpdate` + /// or `ForeignInvestmentCleared`. /// /// 6. Update the redemption. This also includes setting it to zero. We /// assume the impl of `::Investment` handles this case. @@ -372,14 +397,15 @@ impl Pallet { ) -> DispatchResult { let invest_amount = state.get_invest_amount().unwrap_or_default(); + // Do first round of updates and forward state as well as swap match state.clone() { RedeemState::NoState => { RedemptionState::::remove(who, investment_id); - Ok(None) + Ok((Some(RedeemState::NoState), None)) } RedeemState::Invested { .. } => { RedemptionState::::insert(who, investment_id, state); - Ok(None) + Ok((Some(state), None)) } RedeemState::InvestedAnd { inner, .. } | RedeemState::NotInvestedAnd { inner } => { match inner { @@ -387,7 +413,7 @@ impl Pallet { InnerRedeemState::RedeemingAndCollectableRedemption { .. } | InnerRedeemState::CollectableRedemption { .. } => { RedemptionState::::insert(who, investment_id, state); - Ok(None) + Ok((Some(state), None)) }, InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } | InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | @@ -398,55 +424,31 @@ impl Pallet { InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { RedemptionState::::insert(who, investment_id, state); - Ok(Some(swap)) - }, - InnerRedeemState::SwapIntoReturnDone { done_swap } => { - RedemptionState::::remove(who, investment_id); - Ok(None) - }, - // TODO: Check whether we can just remove these four states - InnerRedeemState::RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => { - let new_state = state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); - RedemptionState::::insert(who, investment_id, new_state); - Ok(None) - }, - InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { - let new_state = state.swap_inner_state(InnerRedeemState::RedeemingAndCollectableRedemption { redeem_amount, collect_amount }); - RedemptionState::::insert(who, investment_id, new_state); - Ok(None) - }, - InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { - let new_state = state.swap_inner_state(InnerRedeemState::CollectableRedemption { collect_amount }); - RedemptionState::::insert(who, investment_id, new_state); - Ok(None) + Ok((Some(state), Some(swap))) }, + // Only states left include `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` such that we can notify collect + inner => { + let maybe_new_state = Self::apply_collect_redeem_transition(who, investment_id, state, inner)?; + Ok((maybe_new_state, None)) + } } } } - .map(|maybe_swap| { - let (maybe_invest_state, maybe_redeem_state) = Self::handle_swap_order( + .map(|(maybe_new_state, maybe_swap)| { + let (maybe_new_invest_state, maybe_new_state_prio) = Self::handle_swap_order( who, investment_id, maybe_swap, TokenSwapReason::Redemption, )?; - // update invest and redeem states if necessary - InvestmentState::::mutate(who, investment_id, |current_invest_state| { - if maybe_invest_state != *current_invest_state { - *current_invest_state = maybe_invest_state; - } - // TODO: Maybe emit event of invest state transition from - // `state` to `current_invest_state` - }); - - RedemptionState::::mutate(who, investment_id, |current_redeem_state| { - if maybe_redeem_state != *current_redeem_state { - *current_redeem_state = maybe_redeem_state; - // TODO: Maybe emit event of redeem state transition from - // `current_redeem_state` to `new_state` - } - }); + // Dispatch transition event, post swap state has priority if it exists as it was the last transition + if let Some(redeem_state_post_swap) = maybe_new_state_prio { + Self::deposit_redemption_event(who, investment_id, Some(redeem_state_post_swap)); + } else { + Self::deposit_redemption_event(who, investment_id, maybe_new_state); + } + Self::deposit_investment_event(who, investment_id, maybe_new_invest_state); // Finally, update redemption after all states have been updated T::Investment::update_redemption(who, investment_id, invest_amount)?; @@ -456,6 +458,150 @@ impl Pallet { .map_err(|e: DispatchError| e)? } + /// Emits an event indicating the corresponding `InvestState` was either + /// updated or cleared. + /// + /// NOTE: Noop if the provided state is `None`. + fn deposit_investment_event( + who: &T::AccountId, + investment_id: T::InvestmentId, + maybe_state: Option>, + ) { + match maybe_state { + Some(state) if state == InvestState::NoState => { + Self::deposit_event(Event::::ForeignInvestmentCleared { + investor: who.clone(), + investment_id, + }) + } + Some(state) => Self::deposit_event(Event::::ForeignInvestmentUpdated { + investor: who.clone(), + investment_id, + state, + }), + _ => {} + } + } + + /// Emits an event indicating the corresponding `InvestState` was either + /// updated or cleared. + /// + /// NOTE: Noop if the provided state is `None`. + fn deposit_redemption_event( + who: &T::AccountId, + investment_id: T::InvestmentId, + maybe_state: Option>, + ) { + match maybe_state { + Some(state) if state == RedeemState::NoState => { + Self::deposit_event(Event::::ForeignRedemptionCleared { + investor: who.clone(), + investment_id, + }) + } + Some(state) => Self::deposit_event(Event::::ForeignRedemptionUpdated { + investor: who.clone(), + investment_id, + state, + }), + None => {} + } + } + + /// Terminates a redeem collection which required swapping into return + /// currency. + /// + /// Only acts upon inner redeem states which include `SwapIntoReturnDone` + /// without `ActiveSwapIntoReturnCurrency`. Other inner states are ignored. + /// Either updates the corresponding `RedemptionState` or drops it entirely. + /// + /// Emits `notify_executed_collect_redeem`. + /// + /// Returning... + /// * `Some(RedeemState::NoState)` indicates a `ForeignRedemptionCleared` + /// event can be deposited + /// * `Some(state)` indicates a `ForeignRedemptionUpdated` event can be + /// deposited + /// * `None` indicates no state mutation occurred /// + #[transactional] + fn apply_collect_redeem_transition( + who: &T::AccountId, + investment_id: T::InvestmentId, + state: RedeemState, + inner_redeem_state: InnerRedeemState, + ) -> Result>, DispatchError> { + // TODO: Should just be amount and maybe factor in the remaining amount as well + let collected_redemption = CollectedRedemption::::get(who, investment_id); + + // Send notification and kill `CollectedRedemption` iff the state includes + // `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` + match inner_redeem_state { + InnerRedeemState::SwapIntoReturnDone { done_swap, .. } + | InnerRedeemState::RedeemingAndSwapIntoReturnDone { done_swap, .. } + | InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + done_swap, + .. + } + | InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => { + Self::notify_executed_collect_redeem( + who, + investment_id, + done_swap.currency_in, + CollectedAmount { + amount_collected: done_swap.amount, + amount_payment: collected_redemption.amount_payment, + }, + )?; + CollectedRedemption::::remove(who, investment_id); + + Ok(()) + } + _ => Ok(()), + } + .map_err(|e: DispatchError| e)?; + + // Update state iff the state includes `SwapIntoReturnDone` without + // `ActiveSwapIntoReturnCurrency` + match inner_redeem_state { + InnerRedeemState::SwapIntoReturnDone { .. } => { + RedemptionState::::remove(who, investment_id); + + Ok(Some(RedeemState::NoState)) + } + InnerRedeemState::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } => { + let new_state = + state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); + RedemptionState::::insert(who, investment_id, new_state); + + Ok(Some(new_state)) + } + InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + redeem_amount, + collect_amount, + .. + } => { + let new_state = + state.swap_inner_state(InnerRedeemState::RedeemingAndCollectableRedemption { + redeem_amount, + collect_amount, + }); + RedemptionState::::insert(who, investment_id, new_state); + + Ok(Some(new_state)) + } + InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { + collect_amount, .. + } => { + let new_state = state + .swap_inner_state(InnerRedeemState::CollectableRedemption { collect_amount }); + RedemptionState::::insert(who, investment_id, new_state); + + Ok(Some(new_state)) + } + _ => Ok(None), + } + } + /// Updates or kills a token swap order. If the final swap amount is zero, /// kills the swap order and all associated storage. Else, creates or /// updates an existing swap order. @@ -463,12 +609,13 @@ impl Pallet { /// If the provided reason does not match the latest one stored in /// `TokenSwapReasons`, also resolves the _merge conflict_ resulting from /// updating and thus overwriting opposite swaps. See - /// [Self::handle_concurrent_swap_orders] for details. - /// - /// Returns potentially altered invest and redeem states which are not - /// updated in storage yet! + /// [Self::handle_concurrent_swap_orders] for details. If this results in + /// either an altered invest state and/or an altered redeem state, the + /// corresponding storage is updated and the new states returned. The latter + /// is required for emitting events. /// /// NOTE: Must not call any other swap order updating function. + #[transactional] fn handle_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, @@ -486,7 +633,7 @@ impl Pallet { let (maybe_updated_swap, maybe_invest_state, maybe_redeem_state) = Self::handle_concurrent_swap_orders(who, investment_id, swap_order_id, reason)?; - // update or kill swap order with updated order having priority in case it was + // Update or kill swap order with updated order having priority in case it was // overwritten if let Some(swap_order) = maybe_updated_swap { Self::place_swap_order(who, investment_id, swap_order, reason)?; @@ -496,9 +643,46 @@ impl Pallet { Self::kill_swap_order(who, investment_id)?; } - Ok((maybe_invest_state, maybe_redeem_state)) + // Update invest and redeem states if necessary + InvestmentState::::mutate(who, investment_id, |current_invest_state| { + // Should never occur but let's be safe + if let Some(InvestState::NoState) = maybe_invest_state { + *current_invest_state = None; + } else if maybe_invest_state != *current_invest_state { + *current_invest_state = maybe_invest_state.clone(); + } + }); + + // Need to check if `SwapReturnDone` is part of inner state without + // `ActiveSwapIntoReturnCurrency` as this implies the successful termination of + // a collect (with swap into return currency). If this is the case, the returned + // redeem state needs to be updated as well. + match maybe_redeem_state { + Some(RedeemState::InvestedAnd { inner, .. }) + | Some(RedeemState::NotInvestedAnd { inner }) => { + let redeem_state = maybe_redeem_state.unwrap_or_default(); + let maybe_collected_redeem_state = Self::apply_collect_redeem_transition( + who, + investment_id, + redeem_state, + inner, + )?; + Ok((maybe_invest_state, maybe_collected_redeem_state)) + } + Some(_) => { + RedemptionState::::mutate(who, investment_id, |current_redeem_state| { + // Update and emit event on mismatch + if maybe_redeem_state != *current_redeem_state { + *current_redeem_state = maybe_redeem_state; + } + }); + Ok((maybe_invest_state, maybe_redeem_state)) + } + None => Ok((maybe_invest_state, maybe_redeem_state)), + } + .map_err(|e: DispatchError| e) } - // update to provided value, if not none + // Update to provided value, if not none else if let Some(swap_order) = maybe_swap { Self::place_swap_order(who, investment_id, swap_order, reason)?; Ok((None, None)) @@ -513,7 +697,7 @@ impl Pallet { /// NOTE: Must only be called in `handle_swap_order`. fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { - T::TokenSwaps::cancel_order(swap_order_id); + T::TokenSwaps::cancel_order(swap_order_id)?; ForeignInvestmentInfo::::remove(swap_order_id); TokenSwapReasons::::remove(swap_order_id); } @@ -525,6 +709,7 @@ impl Pallet { /// to the provided value. /// /// NOTE: Must only be called in `handle_swap_order`. + #[transactional] fn place_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, @@ -678,7 +863,7 @@ impl Pallet { } } // We must not alter the invest state if there is no active pool currency swap - state => Ok(None), + _ => Ok(None), } .map_err(|e: DispatchError| e)?; @@ -736,10 +921,12 @@ impl Pallet { /// Sends `ExecutedDecreaseInvestHook` notification such that any potential /// consumer could act upon that, e.g. Connectors for /// `ExecutedDecreaseInvestOrder`. + #[transactional] fn notify_executed_decrease_invest( who: &T::AccountId, investment_id: T::InvestmentId, amount_decreased: T::Balance, + return_currency: T::CurrencyId, ) -> DispatchResult { // TODO(@mustermeiszer): Does this return the entire desired amount or do we // need to tap into collecting? > Requires artificial collect (which does not @@ -756,60 +943,7 @@ impl Pallet { ExecutedDecrease { amount_decreased, amount_remaining, - }, - ) - } - - /// Sends `ExecutedDecreaseRedeemHook` notification such that any potential - /// consumer could act upon that, e.g. Connectors for - /// `ExecutedDecreaseRedeemOrder`. - /// - /// NOTE: In contrast to investments, redemption decrements happen - /// fully synchronously as they can only be called in between increasing a - /// redemption and its (full) processing. The asynchronous token swap - /// happens much later. - fn notify_executed_decrease_redeem( - who: &T::AccountId, - investment_id: T::InvestmentId, - amount_decreased: T::Balance, - ) -> DispatchResult { - // TODO: Check if this is correct and sufficient - let amount_remaining = T::Investment::redemption(who, investment_id)?; - - T::ExecutedDecreaseRedeemHook::notify_status_change( - ForeignInvestmentInfoOf:: { - owner: who.clone(), - id: investment_id, - }, - ExecutedDecrease { - amount_decreased, - amount_remaining, - }, - ) - } - - /// Sends `ExecutedCollectRedeemHook` notification such that any potential - /// consumer could act upon that, e.g. Connectors for - /// `ExecutedCollectRedeemOrder`. - fn notify_executed_collect_invest( - who: &T::AccountId, - investment_id: T::InvestmentId, - amount_tranche_tokens_payout: T::Balance, - ) -> DispatchResult { - // FIXME: Insufficient - let amount_remaining: ::Balance = - T::Investment::investment(who, investment_id)?; - - T::ExecutedCollectInvestHook::notify_status_change( - ForeignInvestmentInfoOf:: { - owner: who.clone(), - id: investment_id, - }, - ExecutedCollect { - currency: None, - amount_currency_payout: todo!("needs to be derived from processing"), - amount_tranche_tokens_payout, - amount_remaining, + return_currency, }, ) } @@ -817,25 +951,24 @@ impl Pallet { /// Sends `ExecutedCollectRedeemHook` notification such that any potential /// consumer could act upon that, e.g. Connectors for /// `ExecutedCollectRedeemOrder`. + #[transactional] fn notify_executed_collect_redeem( who: &T::AccountId, investment_id: T::InvestmentId, currency: T::CurrencyId, - amount_currency_payout: T::Balance, + collected: CollectedAmount, ) -> DispatchResult { - // TODO: Check if this is correct and sufficient - let amount_remaining: ::Balance = - T::Investment::redemption(who, investment_id)?; + let amount_remaining = T::Investment::redemption(&who, investment_id)?; T::ExecutedCollectRedeemHook::notify_status_change( ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, }, - ExecutedCollect { - currency: Some(currency), - amount_currency_payout, - amount_tranche_tokens_payout: todo!("needs to be derived from processing"), + ExecutedCollectRedeem { + currency, + amount_currency_payout: collected.amount_collected, + amount_tranche_tokens_payout: collected.amount_payment, amount_remaining, }, ) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 0b3a9b0e56..29c3a601ba 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -11,34 +11,28 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{ForeignInvestment, Investment, StatusNotificationHook, TokenSwaps}; -use cfg_types::investments::{ExecutedDecrease, InvestmentInfo}; -use frame_support::{ensure, traits::Get, transactional}; +use frame_support::ensure; use sp_runtime::{ - traits::{EnsureAdd, EnsureSub, Zero}, - ArithmeticError, DispatchError, DispatchResult, + traits::{EnsureAdd, EnsureSub}, + ArithmeticError, DispatchError, }; -use crate::{ - types::{ - InnerRedeemState, - InnerRedeemState::{ - ActiveSwapIntoReturnCurrency, ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - CollectableRedemption, CollectableRedemptionAndActiveSwapIntoReturnCurrency, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - CollectableRedemptionAndSwapIntoReturnDone, Redeeming, - RedeemingAndActiveSwapIntoReturnCurrency, - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - RedeemingAndCollectableRedemption, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone, RedeemingAndSwapIntoReturnDone, - SwapIntoReturnDone, - }, - InvestTransition, RedeemState, RedeemTransition, Swap, +use crate::types::{ + InnerRedeemState, + InnerRedeemState::{ + ActiveSwapIntoReturnCurrency, ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + CollectableRedemption, CollectableRedemptionAndActiveSwapIntoReturnCurrency, + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + CollectableRedemptionAndSwapIntoReturnDone, Redeeming, + RedeemingAndActiveSwapIntoReturnCurrency, + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + RedeemingAndCollectableRedemption, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone, RedeemingAndSwapIntoReturnDone, + SwapIntoReturnDone, }, - Config, Error, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, SwapOf, - TokenSwapOrderIds, + RedeemState, RedeemTransition, Swap, }; impl RedeemState @@ -61,9 +55,7 @@ where RedeemTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(&self, swap) } - RedeemTransition::Collect(return_currency, pool_currency) => { - Self::handle_collect(&self, return_currency, pool_currency) - } + RedeemTransition::Collect(swap) => Self::handle_collect(&self, swap), } } @@ -442,6 +434,7 @@ where RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap }), RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount }), // Throw for states without `Redeeming` + // TODO: Create pallet error NotRedeeming inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), } } @@ -578,13 +571,12 @@ where /// (should never happen). fn transition_collect( &self, - return_currency: Currency, - pool_currency: Currency, + collected_swap: Swap, ) -> Result { ensure!( self.get_active_swap() .map(|swap| (swap.currency_in, swap.currency_out) - == (return_currency, pool_currency)) + == (collected_swap.currency_in, collected_swap.currency_out)) .unwrap_or(true), DispatchError::Other("Invalid swap currencies when transitioning collect redemption") ); @@ -597,34 +589,27 @@ where RedeemingAndActiveSwapIntoReturnCurrency { .. } | RedeemingAndSwapIntoReturnDone { .. } | RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), + // TODO: Probably just ignore `collect_amount` CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { - swap: Swap { - amount: collect_amount, - currency_in: return_currency, - currency_out: pool_currency, - } + swap: collected_swap, }), RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, - swap: Swap { - amount: collect_amount, - currency_in: return_currency, - currency_out: pool_currency, - } + swap: collected_swap, }), RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap: Swap { - amount: swap.amount.ensure_add(collect_amount)?, - ..swap + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap } }), RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap: Swap { - amount: collect_amount, - ..done_swap + amount: collected_swap.amount, + ..collected_swap }, done_amount: done_swap.amount }) @@ -633,8 +618,8 @@ where Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap: Swap { - amount: swap.amount.ensure_add(collect_amount)?, - ..swap + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap }, done_amount }) @@ -642,16 +627,16 @@ where CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { Ok(Self::ActiveSwapIntoReturnCurrency { swap: Swap { - amount: swap.amount.ensure_add(collect_amount)?, - ..swap + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap } }) }, CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - amount: collect_amount, - ..done_swap + amount: collected_swap.amount, + ..collected_swap }, done_amount: done_swap.amount, }) @@ -659,8 +644,8 @@ where CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { - amount: swap.amount.ensure_add(collect_amount)?, - ..swap + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap }, done_amount }) @@ -737,7 +722,6 @@ where // state Some(redeem_amount) if redeem_amount == amount => match self { Self::NoState | Self::Invested { .. } => error_not_redeeming, - Self::Invested { invest_amount } => error_not_redeeming, Self::NotInvestedAnd { inner } => match inner { Redeeming { .. } => Ok(Self::Invested { invest_amount: amount, @@ -767,8 +751,9 @@ where let redeem_amount = old_redeem_amount.ensure_sub(amount)?; match self { - Self::NoState | Self::Invested { .. } => error_not_redeeming, - Self::Invested { invest_amount } => error_not_redeeming, + Self::NoState | Self::Invested { .. } | Self::Invested { .. } => { + error_not_redeeming + } Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { invest_amount: amount, inner: inner.set_redeem_amount(redeem_amount)?, @@ -816,21 +801,14 @@ where /// Throws if the state does not allow for collection or the the inner state /// includes an active/done swap with mismatching currencies to the provided /// ones. - fn handle_collect( - &self, - return_currency: Currency, - pool_currency: Currency, - ) -> Result { + fn handle_collect(&self, swap: Swap) -> Result { match self { RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( "Invalid redeem state when transitioning collect", )), - RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => { - Ok(Self::swap_inner_state( - &self, - inner.transition_collect(return_currency, pool_currency)?, - )) - } + RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( + Self::swap_inner_state(&self, inner.transition_collect(swap)?), + ), } } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 915c8827a2..3a74d51c46 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -42,8 +42,11 @@ pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentI // TODO: Remove dev_mode before merging #[frame_support::pallet(dev_mode)] pub mod pallet { - use cfg_traits::{InvestmentCollector, StatusNotificationHook, TokenSwaps, TrancheCurrency}; - use cfg_types::investments::{ExecutedCollect, ExecutedDecrease}; + use cfg_traits::{ + investments::{InvestmentCollector, TrancheCurrency}, + StatusNotificationHook, TokenSwaps, + }; + use cfg_types::investments::{CollectedAmount, ExecutedCollectRedeem, ExecutedDecrease}; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; @@ -112,7 +115,7 @@ pub mod pallet { /// The internal investment type which handles the actual investment on /// top of the wrapper implementation of this Pallet - type Investment: cfg_traits::Investment< + type Investment: cfg_traits::investments::Investment< Self::AccountId, Amount = Self::Balance, CurrencyId = Self::CurrencyId, @@ -122,7 +125,7 @@ pub mod pallet { Self::AccountId, Error = DispatchError, InvestmentId = Self::InvestmentId, - Result = Self::Balance, + Result = CollectedAmount, >; /// The default sell price limit for token swaps which defines the @@ -166,25 +169,13 @@ pub mod pallet { type ExecutedDecreaseInvestHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - Status = ExecutedDecrease, - Error = DispatchError, - >; - - type ExecutedDecreaseRedeemHook: StatusNotificationHook< - Id = ForeignInvestmentInfoOf, - Status = ExecutedDecrease, - Error = DispatchError, - >; - - type ExecutedCollectInvestHook: StatusNotificationHook< - Id = ForeignInvestmentInfoOf, - Status = ExecutedCollect, + Status = ExecutedDecrease, Error = DispatchError, >; type ExecutedCollectRedeemHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - Status = ExecutedCollect, + Status = ExecutedCollectRedeem, Error = DispatchError, >; } @@ -256,6 +247,24 @@ pub mod pallet { T::TokenSwapOrderId, >; + /// Maps an investor and their `InvestmentId` to the amount of collected + /// pool currency and the corresponding amount of tranche tokens burned for + /// the conversion based on the fulfillment price(s). + /// + /// NOTE: The lifetime of this storage starts with collecting a redemption + /// in pool currency and ends with having swapped the entire amount to + /// return currency. + #[pallet::storage] + pub(super) type CollectedRedemption = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, + CollectedAmount, + ValueQuery, + >; + /// Maps a `TokenSwapOrderId` to the corresponding `TokenSwapReason` for /// which it was last updated, i.e. `Investment` or `Redemption`. /// @@ -276,7 +285,24 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - SomethingStored { something: u32, who: T::AccountId }, + ForeignInvestmentUpdated { + investor: T::AccountId, + investment_id: T::InvestmentId, + state: InvestState, + }, + ForeignInvestmentCleared { + investor: T::AccountId, + investment_id: T::InvestmentId, + }, + ForeignRedemptionUpdated { + investor: T::AccountId, + investment_id: T::InvestmentId, + state: RedeemState, + }, + ForeignRedemptionCleared { + investor: T::AccountId, + investment_id: T::InvestmentId, + }, } #[pallet::error] diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 437897de3f..0c0415a22d 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -344,5 +344,5 @@ pub enum RedeemTransition< IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), - Collect(Currency, Currency), + Collect(Swap), } diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 6f5a860884..4f9d767866 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -15,12 +15,15 @@ use cfg_primitives::OrderId; use cfg_traits::{ - Investment, InvestmentAccountant, InvestmentCollector, InvestmentProperties, - InvestmentsPortfolio, OrderManager, PreConditions, + investments::{ + Investment, InvestmentAccountant, InvestmentCollector, InvestmentProperties, + InvestmentsPortfolio, OrderManager, + }, + PreConditions, }; use cfg_types::{ fixed_point::FixedPointNumberExtension, - investments::InvestmentAccount, + investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection}, orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ @@ -31,7 +34,7 @@ use frame_support::{ use frame_system::pallet_prelude::*; pub use pallet::*; use sp_runtime::{ - traits::{AccountIdConversion, CheckedAdd, CheckedSub, One, Zero}, + traits::{AccountIdConversion, CheckedAdd, CheckedSub, EnsureAddAssign, One, Zero}, ArithmeticError, FixedPointNumber, }; use sp_std::{ @@ -57,84 +60,6 @@ type AccountInvestmentPortfolioOf = Vec<( ::Amount, )>; -/// The outstanding collections for an account -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct InvestCollection { - /// This is the payout in the denomination currency - /// of an investment - /// -> investment in payment currency - /// -> payout in denomination currency - pub payout_investment_invest: Balance, - - /// This is the remaining investment in the payment currency - /// of an investment - /// -> investment in payment currency - /// -> payout in denomination currency - pub remaining_investment_invest: Balance, -} - -impl Default for InvestCollection { - fn default() -> Self { - InvestCollection { - payout_investment_invest: Zero::zero(), - remaining_investment_invest: Zero::zero(), - } - } -} - -impl InvestCollection { - /// Create a `InvestCollection` directly from an active invest order of - /// a user. - /// The field `remaining_investment_invest` is set to the - /// amount of the active invest order of the user and will - /// be subtracted from upon given fulfillment's - pub fn from_order(order: &Order) -> Self { - InvestCollection { - payout_investment_invest: Zero::zero(), - remaining_investment_invest: order.amount(), - } - } -} - -/// The outstanding collections for an account -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct RedeemCollection { - /// This is the payout in the payment currency - /// of an investment - /// -> redemption in denomination currency - /// -> payout in payment currency - pub payout_investment_redeem: Balance, - - /// This is the remaining redemption in the denomination currency - /// of an investment - /// -> redemption in denomination currency - /// -> payout in payment currency - pub remaining_investment_redeem: Balance, -} - -impl Default for RedeemCollection { - fn default() -> Self { - RedeemCollection { - payout_investment_redeem: Zero::zero(), - remaining_investment_redeem: Zero::zero(), - } - } -} - -impl RedeemCollection { - /// Create a `RedeemCollection` directly from an active redeem order of - /// a user. - /// The field `remaining_investment_redeem` is set to the - /// amount of the active redeem order of the user and will - /// be subtracted from upon given fulfillment's - pub fn from_order(order: &Order) -> Self { - RedeemCollection { - payout_investment_redeem: Zero::zero(), - remaining_investment_redeem: order.amount(), - } - } -} - /// The enum we parse to `PreConditions` so the runtime /// can make an educated decision about this investment #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] @@ -705,203 +630,222 @@ where } } - // TODO: Add amount and if possible currency to return #[allow(clippy::type_complexity)] pub(crate) fn do_collect_invest( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; - InvestOrders::::try_mutate( - &who, - investment_id, - |maybe_order| -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { - // Exit early if order does not exist - let order = if let Some(order) = maybe_order.as_mut() { - order - } else { - Self::deposit_event(Event::::InvestCollectedWithoutActivePosition { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + Storage::read() + Storage::write() - return Ok((Zero::zero(), ().into())); - }; - - let mut collection = InvestCollection::::from_order(order); - let mut collected_ids = Vec::new(); - let cur_order_id = InvestOrderId::::get(investment_id); - let last_processed_order_id = min( - order - .submitted_at() - .saturating_add(T::MaxOutstandingCollects::get()), - cur_order_id, - ); - - // Exit early if the current order is not in processing - if order.submitted_at() == cur_order_id { - Self::deposit_event(Event::::InvestCollectedForNonClearedOrderId { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok((order.amount(), ().into())); - } - - for order_id in order.submitted_at()..last_processed_order_id { - let fulfillment = ClearedInvestOrders::::try_get(investment_id, order_id) - .map_err(|_| Error::::OrderNotCleared)?; + InvestOrders::::try_mutate(&who, investment_id, |maybe_order| { + // Exit early if order does not exist + let order = if let Some(order) = maybe_order.as_mut() { + order + } else { + Self::deposit_event(Event::::InvestCollectedWithoutActivePosition { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + }; + + let mut collection = InvestCollection::::from_order(order); + let mut collected_ids = Vec::new(); + let cur_order_id = InvestOrderId::::get(investment_id); + let last_processed_order_id = min( + order + .submitted_at() + .saturating_add(T::MaxOutstandingCollects::get()), + cur_order_id, + ); + + // Exit early if the current order is not in processing + if order.submitted_at() == cur_order_id { + Self::deposit_event(Event::::InvestCollectedForNonClearedOrderId { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + 2 * Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + } + + let mut amount_payment: T::Amount = Default::default(); + for order_id in order.submitted_at()..last_processed_order_id { + let fulfillment = ClearedInvestOrders::::try_get(investment_id, order_id) + .map_err(|_| Error::::OrderNotCleared)?; + let currency_payout = Pallet::::acc_payout_invest(&mut collection, &fulfillment)?; - Pallet::::acc_remaining_invest(&mut collection, &fulfillment)?; - collected_ids.push(order_id); - } - - order.update_after_collect( - collection.remaining_investment_invest, - last_processed_order_id, - ); - - T::Accountant::transfer( - info.id(), - &InvestmentAccount { investment_id }.into_account_truncating(), - &who, - collection.payout_investment_invest, + Pallet::::acc_remaining_invest(&mut collection, &fulfillment)?; + collected_ids.push(order_id); + + amount_payment.ensure_add_assign( + fulfillment + .price + .checked_mul_int_floor(currency_payout) + .ok_or(ArithmeticError::Overflow)?, )?; + } - let amount = order.amount(); - Self::rm_empty( - amount, - maybe_order, - Event::InvestOrderUpdated { - investment_id, - submitted_at: last_processed_order_id, - who: who.clone(), - amount, - }, - ); - let amount_payout = collection.payout_investment_invest; - - Self::deposit_event(Event::InvestOrdersCollected { + order.update_after_collect( + collection.remaining_investment_invest, + last_processed_order_id, + ); + + T::Accountant::transfer( + info.id(), + &InvestmentAccount { investment_id }.into_account_truncating(), + &who, + collection.payout_investment_invest, + )?; + + let amount = order.amount(); + Self::rm_empty( + amount, + maybe_order, + Event::InvestOrderUpdated { investment_id, + submitted_at: last_processed_order_id, who: who.clone(), - processed_orders: collected_ids, - collection, - outcome: if last_processed_order_id == cur_order_id { - CollectOutcome::FullyCollected - } else { - CollectOutcome::PartiallyCollected - }, - }); + amount, + }, + ); + + let collected_investment = CollectedAmount { + amount_collected: collection.payout_investment_invest, + amount_payment, + }; + + Self::deposit_event(Event::InvestOrdersCollected { + investment_id, + who: who.clone(), + processed_orders: collected_ids, + collection, + outcome: if last_processed_order_id == cur_order_id { + CollectOutcome::FullyCollected + } else { + CollectOutcome::PartiallyCollected + }, + }); - // TODO: Actually weight with amount of collects here - Ok((amount_payout, ().into())) - }, - ) + // TODO: Actually weight with amount of collects here + Ok((collected_investment, ().into())) + }) } - // TODO: Add amount and if possible currency to return #[allow(clippy::type_complexity)] pub(crate) fn do_collect_redeem( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; - RedeemOrders::::try_mutate( - &who, - investment_id, - |maybe_order| -> Result<(T::Amount, PostDispatchInfo), DispatchErrorWithPostInfo> { - // Exit early if order does not exist - let order = if let Some(order) = maybe_order.as_mut() { - order - } else { - // Trigger event - Self::deposit_event(Event::::RedeemCollectedWithoutActivePosition { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + Storage::read() + Storage::write() - return Ok((Zero::zero(), ().into())); - }; - - let mut collection = RedeemCollection::::from_order(order); - let mut collected_ids = Vec::new(); - let cur_order_id = RedeemOrderId::::get(investment_id); - let last_processed_order_id = min( - order - .submitted_at() - .saturating_add(T::MaxOutstandingCollects::get()), - cur_order_id, - ); - - // Exit early if the current order is not in processing - if order.submitted_at() == cur_order_id { - Self::deposit_event(Event::::RedeemCollectedForNonClearedOrderId { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok((order.amount(), ().into())); - } - - for order_id in order.submitted_at()..last_processed_order_id { - let fulfillment = ClearedRedeemOrders::::try_get(investment_id, order_id) - .map_err(|_| Error::::OrderNotCleared)?; - Pallet::::acc_payout_redeem(&mut collection, &fulfillment)?; - Pallet::::acc_remaining_redeem(&mut collection, &fulfillment)?; - collected_ids.push(order_id); - } - - order.update_after_collect( - collection.remaining_investment_redeem, - last_processed_order_id, - ); + RedeemOrders::::try_mutate(&who, investment_id, |maybe_order| { + // Exit early if order does not exist + let order = if let Some(order) = maybe_order.as_mut() { + order + } else { + // Trigger event + Self::deposit_event(Event::::RedeemCollectedWithoutActivePosition { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + }; + + let mut collection = RedeemCollection::::from_order(order); + let mut collected_ids = Vec::new(); + let cur_order_id = RedeemOrderId::::get(investment_id); + let last_processed_order_id = min( + order + .submitted_at() + .saturating_add(T::MaxOutstandingCollects::get()), + cur_order_id, + ); + + // Exit early if the current order is not in processing + if order.submitted_at() == cur_order_id { + Self::deposit_event(Event::::RedeemCollectedForNonClearedOrderId { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + 2 * Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + } - // Transfer collected amounts from investment and redemption - let investment_account = - InvestmentAccount { investment_id }.into_account_truncating(); - T::Tokens::transfer( - info.payment_currency(), - &investment_account, - &who, - // TODO: return collected amount - collection.payout_investment_redeem, - false, + let mut amount_payment: T::Amount = Default::default(); + for order_id in order.submitted_at()..last_processed_order_id { + let fulfillment = ClearedRedeemOrders::::try_get(investment_id, order_id) + .map_err(|_| Error::::OrderNotCleared)?; + let payout_tranche_tokens = + Pallet::::acc_payout_redeem(&mut collection, &fulfillment)?; + Pallet::::acc_remaining_redeem(&mut collection, &fulfillment)?; + collected_ids.push(order_id); + + // TODO(@mustermeiszer): We actually want the reciprocal without rounding, is + // this sufficient or should we use something like + // `reciprocal_with_rounding(SignedRounding::NearestPrefMajor)` + amount_payment.ensure_add_assign( + fulfillment + .price + .reciprocal_floor() + .ok_or(Error::::ZeroPricedInvestment)? + .checked_mul_int_floor(payout_tranche_tokens) + .ok_or(ArithmeticError::Overflow)?, )?; + } - let amount = order.amount(); - Self::rm_empty( - amount, - maybe_order, - Event::RedeemOrderUpdated { - investment_id, - submitted_at: last_processed_order_id, - who: who.clone(), - amount, - }, - ); - let amount_payout = collection.payout_investment_redeem; - - Self::deposit_event(Event::RedeemOrdersCollected { + order.update_after_collect( + collection.remaining_investment_redeem, + last_processed_order_id, + ); + + // Transfer collected amounts from investment and redemption + let investment_account = InvestmentAccount { investment_id }.into_account_truncating(); + T::Tokens::transfer( + info.payment_currency(), + &investment_account, + &who, + collection.payout_investment_redeem, + false, + )?; + + let amount = order.amount(); + Self::rm_empty( + amount, + maybe_order, + Event::RedeemOrderUpdated { investment_id, + submitted_at: last_processed_order_id, who: who.clone(), - processed_orders: collected_ids, - collection, - outcome: if last_processed_order_id == cur_order_id { - CollectOutcome::FullyCollected - } else { - CollectOutcome::PartiallyCollected - }, - }); + amount, + }, + ); + + let collected_redemption = CollectedAmount { + amount_collected: collection.payout_investment_redeem, + amount_payment, + }; + + Self::deposit_event(Event::RedeemOrdersCollected { + investment_id, + who: who.clone(), + processed_orders: collected_ids, + collection, + outcome: if last_processed_order_id == cur_order_id { + CollectOutcome::FullyCollected + } else { + CollectOutcome::PartiallyCollected + }, + }); - // TODO: Actually weight this with collected_ids - Ok((amount_payout, ().into())) - }, - ) + // TODO: Actually weight this with collected_ids + Ok((collected_redemption, ().into())) + }) } pub(crate) fn do_update_invest_order( @@ -981,10 +925,14 @@ where } } + /// Increments an accounts' investment payout amount based on the remaining + /// amount and the fulfillment price. + /// + /// Returns the amount by which was incremented. pub fn acc_payout_invest( collection: &mut InvestCollection, fulfillment: &FulfillmentWithPrice, - ) -> DispatchResult { + ) -> Result { let remaining = collection.remaining_investment_invest; // NOTE: The checked_mul_int_floor and reciprocal_floor here ensure that for a // given price the system side (i.e. the pallet-investments) will always @@ -996,26 +944,29 @@ where // // TODO: Rounding always means, we might have issuance on tranche-tokens // left, that are rounding leftovers. This will be of importance, once we remove - // tranches at some point. + // tranches at some point. + let payout_investment_invest = &fulfillment + .price + .reciprocal_floor() + .ok_or(Error::::ZeroPricedInvestment)? + .checked_mul_int_floor(fulfillment.of_amount.mul_floor(remaining)) + .ok_or(ArithmeticError::Overflow)?; collection.payout_investment_invest = collection .payout_investment_invest - .checked_add( - &fulfillment - .price - .reciprocal_floor() - .ok_or(Error::::ZeroPricedInvestment)? - .checked_mul_int_floor(fulfillment.of_amount.mul_floor(remaining)) - .ok_or(ArithmeticError::Overflow)?, - ) + .checked_add(payout_investment_invest) .ok_or(ArithmeticError::Overflow)?; - Ok(()) + Ok(*payout_investment_invest) } + /// Increments an accounts' redemption payout amount based on the remaining + /// amount and the fulfillment price. + /// + /// Returns the amount by which was incremented. pub fn acc_payout_redeem( collection: &mut RedeemCollection, fulfillment: &FulfillmentWithPrice, - ) -> DispatchResult { + ) -> Result { let remaining = collection.remaining_investment_redeem; // NOTE: The checked_mul_int_floor here ensures that for a given price // the system side (i.e. the pallet-investments) will always have @@ -1028,19 +979,20 @@ where // TODO: Rounding always means, we might have issuance on tranche-tokens left, // that are rounding leftovers. This will be of importance, once we remove // tranches at some point. + let payout_investment_redeem = &fulfillment + .price + .checked_mul_int_floor(fulfillment.of_amount.mul_floor(remaining)) + .ok_or(ArithmeticError::Overflow)?; collection.payout_investment_redeem = collection .payout_investment_redeem - .checked_add( - &fulfillment - .price - .checked_mul_int_floor(fulfillment.of_amount.mul_floor(remaining)) - .ok_or(ArithmeticError::Overflow)?, - ) + .checked_add(payout_investment_redeem) .ok_or(ArithmeticError::Overflow)?; - Ok(()) + Ok(*payout_investment_redeem) } + /// Decrements an accounts' remaining redemption amount based on the + /// fulfillment price. pub fn acc_remaining_redeem( collection: &mut RedeemCollection, fulfillment: &FulfillmentWithPrice, @@ -1054,6 +1006,8 @@ where Ok(()) } + /// Decrements an accounts' remaining investment amount based on the + /// fulfillment price. pub fn acc_remaining_invest( collection: &mut InvestCollection, fulfillment: &FulfillmentWithPrice, @@ -1483,23 +1437,25 @@ where { type Error = DispatchError; type InvestmentId = T::InvestmentId; - type Result = T::Amount; + type Result = CollectedAmount; + // TODO: Write unit test in investments to test this fn collect_investment( who: T::AccountId, - investment_id: Self::InvestmentId, - ) -> Result { + investment_id: T::InvestmentId, + ) -> Result, DispatchError> { Pallet::::do_collect_invest(who, investment_id) .map_err(|e| e.error) - .map(|(amount, _)| amount) + .map(|(collected_amount, _)| collected_amount) } + // TODO: Write unit test in investments to test this fn collect_redemption( who: T::AccountId, - investment_id: Self::InvestmentId, - ) -> Result { + investment_id: T::InvestmentId, + ) -> Result, DispatchError> { Pallet::::do_collect_redeem(who, investment_id) .map_err(|e| e.error) - .map(|(amount, _)| amount) + .map(|(collected_amount, _)| collected_amount) } } diff --git a/pallets/investments/src/tests.rs b/pallets/investments/src/tests.rs index 0faa9308ce..03475ea857 100644 --- a/pallets/investments/src/tests.rs +++ b/pallets/investments/src/tests.rs @@ -839,6 +839,16 @@ fn fulfillment_partially_works_low_price() { of_amount: PERC_REDEEM_FULFILL, price: PRICE, }; + #[allow(non_snake_case)] + let T_BALANCE_POST_COLLECT_INVEST = PRICE + .reciprocal_floor() + .unwrap() + .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) + .unwrap(); + #[allow(non_snake_case)] + let AUSD_BALANCE_POST_COLLECT_REDEEM = PRICE + .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) + .unwrap(); // Setup investments and redemptions. // We do not thoroughly check the events here, as we @@ -946,11 +956,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorA::get(), INVESTMENT_0_0), @@ -1009,11 +1015,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorA::get(), INVESTMENT_0_0), @@ -1051,11 +1053,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorB::get(), INVESTMENT_0_0), @@ -1114,11 +1112,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorB::get(), INVESTMENT_0_0), @@ -1179,9 +1173,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - PRICE - .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) - .unwrap() + AUSD_BALANCE_POST_COLLECT_REDEEM ); assert_eq!( RedeemOrders::::get(TrancheHolderA::get(), INVESTMENT_0_0), @@ -1238,9 +1230,7 @@ fn fulfillment_partially_works_low_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - PRICE - .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) - .unwrap() + AUSD_BALANCE_POST_COLLECT_REDEEM ); assert_eq!( RedeemOrders::::get(TrancheHolderA::get(), INVESTMENT_0_0), @@ -1534,6 +1524,16 @@ fn fulfillment_partially_works_high_price() { of_amount: PERC_REDEEM_FULFILL, price: PRICE, }; + #[allow(non_snake_case)] + let T_BALANCE_POST_COLLECT_INVEST = PRICE + .reciprocal_floor() + .unwrap() + .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) + .unwrap(); + #[allow(non_snake_case)] + let AUSD_BALANCE_POST_COLLECT_REDEEM = PRICE + .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) + .unwrap(); // Setup investments and redemptions. // We do not thoroughly check the events here, as we @@ -1641,11 +1641,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorA::get(), INVESTMENT_0_0), @@ -1704,11 +1700,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorA::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorA::get(), INVESTMENT_0_0), @@ -1746,11 +1738,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorB::get(), INVESTMENT_0_0), @@ -1809,11 +1797,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(InvestorB::get(), INVESTMENT_0_0.into()), - PRICE - .reciprocal_floor() - .unwrap() - .checked_mul_int_floor(PERC_INVEST_FULFILL.mul_floor(SINGLE_INVEST_AMOUNT)) - .unwrap() + T_BALANCE_POST_COLLECT_INVEST ); assert_eq!( InvestOrders::::get(InvestorB::get(), INVESTMENT_0_0), @@ -1874,9 +1858,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - PRICE - .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) - .unwrap() + AUSD_BALANCE_POST_COLLECT_REDEEM ); assert_eq!( RedeemOrders::::get(TrancheHolderA::get(), INVESTMENT_0_0), @@ -1933,9 +1915,7 @@ fn fulfillment_partially_works_high_price() { )); assert_eq!( free_balance_of(TrancheHolderA::get(), AUSD_CURRENCY_ID), - PRICE - .checked_mul_int_floor(PERC_REDEEM_FULFILL.mul_floor(SINGLE_REDEEM_AMOUNT)) - .unwrap() + AUSD_BALANCE_POST_COLLECT_REDEEM ); assert_eq!( RedeemOrders::::get(TrancheHolderA::get(), INVESTMENT_0_0), diff --git a/pallets/pool-registry/src/lib.rs b/pallets/pool-registry/src/lib.rs index 2851477a5f..a9bbee7b69 100644 --- a/pallets/pool-registry/src/lib.rs +++ b/pallets/pool-registry/src/lib.rs @@ -13,7 +13,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use cfg_primitives::Moment; -use cfg_traits::{Permissions, PoolMutate, TrancheCurrency, UpdateState}; +use cfg_traits::{investments::TrancheCurrency, Permissions, PoolMutate, UpdateState}; use cfg_types::{ permissions::{PermissionScope, PoolRole, Role}, pools::{PoolMetadata, PoolRegistrationStatus}, diff --git a/pallets/pool-system/src/impls.rs b/pallets/pool-system/src/impls.rs index a1c2ae8974..487a871bee 100644 --- a/pallets/pool-system/src/impls.rs +++ b/pallets/pool-system/src/impls.rs @@ -11,8 +11,9 @@ // GNU General Public License for more details. use cfg_traits::{ - changes::ChangeGuard, CurrencyPair, InvestmentAccountant, PoolUpdateGuard, PriceValue, - TrancheCurrency, TrancheTokenPrice, UpdateState, + changes::ChangeGuard, + investments::{InvestmentAccountant, TrancheCurrency}, + CurrencyPair, PoolUpdateGuard, PriceValue, TrancheTokenPrice, UpdateState, }; use cfg_types::{epoch::EpochState, investments::InvestmentInfo}; use frame_support::traits::Contains; diff --git a/pallets/pool-system/src/lib.rs b/pallets/pool-system/src/lib.rs index e254bfc609..21baca064f 100644 --- a/pallets/pool-system/src/lib.rs +++ b/pallets/pool-system/src/lib.rs @@ -179,7 +179,10 @@ impl Default for Release { #[frame_support::pallet] pub mod pallet { - use cfg_traits::{OrderManager, PoolUpdateGuard, TrancheCurrency as TrancheCurrencyT}; + use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + PoolUpdateGuard, + }; use cfg_types::{ orders::{FulfillmentWithPrice, TotalOrder}, tokens::CustomMetadata, diff --git a/pallets/pool-system/src/pool_types.rs b/pallets/pool-system/src/pool_types.rs index adc170a525..7c0d08a14c 100644 --- a/pallets/pool-system/src/pool_types.rs +++ b/pallets/pool-system/src/pool_types.rs @@ -251,7 +251,7 @@ impl< EpochId: BaseArithmetic + Copy, PoolId: Copy + Encode, Rate: FixedPointNumber, - TrancheCurrency: Copy + cfg_traits::TrancheCurrency, + TrancheCurrency: Copy + cfg_traits::investments::TrancheCurrency, TrancheId: Clone + From<[u8; 16]> + PartialEq, Weight: Copy + From, MaxTranches: Get, diff --git a/pallets/pool-system/src/tranches.rs b/pallets/pool-system/src/tranches.rs index 273444d968..ed7c3d611c 100644 --- a/pallets/pool-system/src/tranches.rs +++ b/pallets/pool-system/src/tranches.rs @@ -13,7 +13,7 @@ use cfg_primitives::Moment; #[cfg(test)] use cfg_primitives::{Balance, PoolId, TrancheId, TrancheWeight}; -use cfg_traits::TrancheCurrency as TrancheCurrencyT; +use cfg_traits::investments::TrancheCurrency as TrancheCurrencyT; #[cfg(test)] use cfg_types::{fixed_point::Rate, tokens::TrancheCurrency}; use cfg_types::{ diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 110df8953b..b12faf62e3 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -21,8 +21,8 @@ pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ - OrderManager, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, - TrancheCurrency as _, + investments::{OrderManager, TrancheCurrency as _}, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, }; pub use cfg_types::tokens::CurrencyId; use cfg_types::{ diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index f789b4f980..f294dd2817 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -21,8 +21,8 @@ pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ - OrderManager, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, - TrancheCurrency as _, + investments::{OrderManager, TrancheCurrency as _}, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, }; use cfg_types::{ consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes}, diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index d1039daec5..25b94b1545 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -410,7 +410,7 @@ pub mod changes { /// Module for investment portfolio common to all runtimes pub mod investment_portfolios { - use cfg_traits::{InvestmentsPortfolio, TrancheCurrency}; + use cfg_traits::investments::{InvestmentsPortfolio, TrancheCurrency}; use sp_std::vec::Vec; /// Get the PoolId, CurrencyId, InvestmentId, and Balance for all diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index 122aa9ac95..06955dcd6b 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -126,7 +126,7 @@ pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-fea pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } -pallet-foreign-investment = { path = "../../pallets/foreign-investments", default-features = false } +pallet-foreign-investments = { path = "../../pallets/foreign-investments", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-keystore = { path = "../../pallets/keystore", default-features = false } @@ -206,7 +206,7 @@ std = [ "pallet-evm-precompile-dispatch/std", "pallet-evm-chain-id/std", "pallet-fees/std", - "pallet-foreign-investment/std", + "pallet-foreign-investments/std", "pallet-identity/std", "pallet-interest-accrual/std", "pallet-investments/std", @@ -298,7 +298,7 @@ runtime-benchmarks = [ "pallet-ethereum-transaction/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", - # "pallet-foreign-investment/runtime-benchmarks", + # "pallet-foreign-investments/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", "pallet-keystore/runtime-benchmarks", @@ -402,7 +402,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-fees/try-runtime", - "pallet-foreign-investment/try-runtime", + "pallet-foreign-investments/try-runtime", "pallet-identity/try-runtime", "pallet-migration-manager/try-runtime", "pallet-multisig/try-runtime", diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 329e53c29a..8f252205f6 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -25,8 +25,9 @@ pub use cfg_primitives::{ types::{PoolId, *}, }; use cfg_traits::{ - CurrencyPrice, OrderManager, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, - PreConditions, PriceValue, TrancheCurrency as _, TrancheTokenPrice, + investments::{OrderManager, TrancheCurrency as _}, + CurrencyPrice, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, + PriceValue, TrancheTokenPrice, }; use cfg_types::{ consts::pools::*, @@ -103,7 +104,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, - Dispatchable, One, PostDispatchInfoOf, UniqueSaturatedInto, Zero, + Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, FixedI128, Perbill, Permill, @@ -1582,37 +1583,23 @@ impl orml_asset_registry::Config for Runtime { parameter_types! { // TODO: Discuss, refine - pub const DefaultTokenMinFulfillmentAmount: Balance = Balance::one(); - pub const DefaultTokenSwapSellPriceLimit: Balance = Balance::one(); + pub const DefaultTokenMinFulfillmentAmount: Balance = 1; + pub const DefaultTokenSwapSellPriceLimit: Balance = 1; } -// TODO: Remove me -struct DummyHook; -impl cfg_traits::StatusNotificationHook for DummyHook { - type Error = DispatchError; - type Id = u128; - type Status = (); - - fn notify_status_change(id: u128, status: ()) -> Result<(), DispatchError> { - unimplemented!("Remove the entire impl before merging") - } -} - -impl pallet_foreign_investment::Config for Runtime { +impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CurrencyId = CurrencyId; type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; - type ExecutedCollectInvestHook = DummyHook; - type ExecutedCollectRedeemHook = DummyHook; - type ExecutedDecreaseInvestHook = DummyHook; - type ExecutedDecreaseRedeemHook = DummyHook; + type ExecutedCollectRedeemHook = pallet_connectors::hooks::CollectRedeemHook; + type ExecutedDecreaseInvestHook = pallet_connectors::hooks::DecreaseInvestOrderHook; type Investment = Investments; type InvestmentId = TrancheCurrency; type PoolId = PoolId; type RuntimeEvent = RuntimeEvent; - type TokenSwapOrderId = u128; - type TokenSwaps = (); + type TokenSwapOrderId = u64; + type TokenSwaps = OrderBook; type TrancheId = TrancheId; type WeightInfo = (); } @@ -1973,7 +1960,7 @@ construct_runtime!( GapRewardMechanism: pallet_rewards::mechanism::gap = 114, ConnectorsGateway: pallet_connectors_gateway::{Pallet, Call, Storage, Event, Origin } = 115, OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 116, - ForeignInvestments: pallet_foreign_investment::{Pallet, Call, Storage, Event} = 117, + ForeignInvestments: pallet_foreign_investments::{Pallet, Call, Storage, Event} = 117, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, From e5b01104d4958b22459f87f1b3f0e0950e05a082 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 11:25:28 +0200 Subject: [PATCH 19/96] chore: remove some TODOs --- libs/traits/src/investments.rs | 3 - libs/traits/src/lib.rs | 4 +- libs/types/src/investments.rs | 73 +++++----- .../foreign-investments/src/impls/invest.rs | 3 +- pallets/foreign-investments/src/impls/mod.rs | 132 ++++++++---------- .../foreign-investments/src/impls/redeem.rs | 3 +- pallets/foreign-investments/src/lib.rs | 26 ++-- pallets/foreign-investments/src/types.rs | 21 +-- pallets/liquidity-pools/src/hooks.rs | 16 +-- pallets/liquidity-pools/src/inbound.rs | 6 +- pallets/liquidity-pools/src/lib.rs | 4 +- pallets/liquidity-pools/src/message.rs | 42 ++---- 12 files changed, 142 insertions(+), 191 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index beba64be44..7cc5eae6ac 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -324,9 +324,6 @@ pub trait ForeignInvestment { /// investment amount. fn increase_foreign_redemption( who: &AccountId, - // TODO: Check if we do not require them if can be derived in CollectRedeemOrder - // return_currency: Self::CurrencyId, - // pool_currency: Self::CurrencyId, investment_id: Self::InvestmentId, amount: Self::Amount, ) -> Result<(), Self::Error>; diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 3767fb42cc..43381793f0 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -499,7 +499,9 @@ pub trait TokenSwaps { fn is_active(order: Self::OrderId) -> bool; } -// TODO: Docs +/// Trait to transmit a change of status for anything uniquely identifiable. +/// +/// NOTE: The main use case to handle asynchronous operations. pub trait StatusNotificationHook { /// The identifying type type Id; diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 68ee34b87e..891dbb3264 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -15,6 +15,7 @@ use cfg_traits::investments::InvestmentProperties; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; +use sp_arithmetic::traits::{EnsureAdd, EnsureSub}; use sp_runtime::traits::Zero; use sp_std::cmp::PartialEq; @@ -136,8 +137,8 @@ impl RedeemCollection { } /// The collected investment/redemption amount for an account -#[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct CollectedAmount { +#[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectedAmount { /// The amount which was was collected /// * If investment: Tranche tokens /// * If redemption: Payment currency @@ -150,29 +151,6 @@ pub struct CollectedAmount { pub amount_payment: Balance, } -// /// The collected investment for an account -// #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, -// TypeInfo)] pub struct CollectedInvestment { -// /// The amount of tranche tokens which was was collected -// pub amount_collected: Balance, - -// /// The amount of payment currency which invested and converted into tranche -// /// tokens during processing based on the fulfillment price(s) -// pub amount_payment: Balance, -// } - -// /// The collected redemption for an account -// #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, -// TypeInfo)] pub struct CollectedRedemption { -// /// The amount of payment currency which was was collected -// pub amount_collected: Balance, - -// /// The tranche tokens which which was held as an investment and converted -// /// into payment currency during processing based on the fulfillment -// /// price(s) -// pub amount_payment: Balance, -// } - /// A representation of an investment identifier and the corresponding owner. /// /// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. @@ -183,41 +161,60 @@ pub struct ForeignInvestmentInfo { pub id: InvestmentId, } -/// A representation of an executed decreased investment or redemption. +/// A simple representation of a currency swap. +#[derive( + Clone, + Default, + Copy, + PartialOrd, + Ord, + PartialEq, + Eq, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, +)] +pub struct Swap { + /// The incoming currency, i.e. the desired one. + pub currency_in: Currency, + /// The outgoing currency, i.e. the one which should be replaced. + pub currency_out: Currency, + /// The amount of outgoing currency which shall be exchanged. + pub amount: Balance, +} + +/// A representation of an executed investment decrement. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ExecutedDecrease { +pub struct ExecutedForeignDecrease { + /// The currency in which `DecreaseInvestOrder` was realised pub return_currency: Currency, + /// The amount of `currency` that was actually executed in the original + /// `DecreaseInvestOrder` message, i.e., the amount by which the + /// investment order was actually decreased by. pub amount_decreased: Balance, - pub amount_remaining: Balance, } /// A representation of an executed collected investment. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ExecutedCollectInvest { +pub struct ExecutedForeignCollectInvest { /// The amount that was actually collected pub amount_currency_payout: Balance, /// The amount of tranche tokens received for the investment made pub amount_tranche_tokens_payout: Balance, - // TODO: Processed or unprocessed? - /// The remaining, unprocessed investment amount which the investor - /// still has locked to invest at a later epoch execution - pub amount_remaining: Balance, } /// A representation of an executed collected redemption. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ExecutedCollectRedeem { +pub struct ExecutedForeignCollectRedeem { /// The return currency in which the payout takes place pub currency: Currency, /// The amount of `currency` being paid out to the investor pub amount_currency_payout: Balance, /// How many tranche tokens were actually redeemed pub amount_tranche_tokens_payout: Balance, - // TODO: Processed or unprocessed? - /// The remaining amount of tranche tokens the investor still has locked - /// to redeem at a later epoch execution - pub amount_remaining: Balance, } diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index e131d4040b..41007438b1 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -11,12 +11,13 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use cfg_types::investments::Swap; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, ArithmeticError, DispatchError, DispatchResult, }; -use crate::types::{InvestState, InvestTransition, Swap}; +use crate::types::{InvestState, InvestTransition}; impl InvestState where diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index e9c81ce38c..3000c88317 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -16,7 +16,8 @@ use cfg_traits::{ StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedAmount, ExecutedCollectInvest, ExecutedCollectRedeem, ExecutedDecrease, + CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, + ExecutedForeignDecrease, Swap, }; use frame_support::{traits::Get, transactional}; use sp_runtime::{ @@ -26,7 +27,7 @@ use sp_runtime::{ use crate::{ types::{ - InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, Swap, + InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, }, CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, @@ -64,10 +65,6 @@ impl StatusNotificationHook for Pallet { let post_state = pre_state.transition(RedeemTransition::FulfillSwapOrder(status))?; Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) - - // TODO: When RedeemState includes `SwapIntoReturnDone` without - // `ActiveSwapIntoReturnCurrency`, we must emit - // `ExecutedCollectRedeem`. } } } @@ -75,7 +72,7 @@ impl StatusNotificationHook for Pallet { impl ForeignInvestment for Pallet { type Amount = T::Balance; - type CollectInvestResult = ExecutedCollectInvest; + type CollectInvestResult = ExecutedForeignCollectInvest; type CurrencyId = T::CurrencyId; type Error = DispatchError; type InvestmentId = T::InvestmentId; @@ -123,8 +120,6 @@ impl ForeignInvestment for Pallet { #[transactional] fn increase_foreign_redemption( who: &T::AccountId, - // return_currency: T::CurrencyId, - // pool_currency: T::CurrencyId, investment_id: T::InvestmentId, amount: T::Balance, ) -> Result<(), DispatchError> { @@ -155,19 +150,18 @@ impl ForeignInvestment for Pallet { fn collect_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is // independent of the current `InvestState` let CollectedAmount:: { amount_collected, amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; - let amount_currency_unprocessed = T::Investment::investment(who, investment_id)?; - Ok(ExecutedCollectInvest { + Ok(ExecutedForeignCollectInvest { + // TODO: Translate from `pool_currency` to `return_currency` amount_currency_payout: amount_payment, amount_tranche_tokens_payout: amount_collected, - amount_remaining: amount_currency_unprocessed, }) } @@ -207,6 +201,7 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, ) -> Result { + // TODO: Needs to be translated from `pool_currency` to `return_currency` T::Investment::investment(who, investment_id) } @@ -214,19 +209,30 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, ) -> Result { + // TODO: Needs to be translated from `pool_currency` to `return_currency` T::Investment::redemption(who, investment_id) } - // TODO: Maybe add pool_currency derived via - // PoolInspect::currency_for(investment_id.into()) - fn accepted_payment_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { - // FIXME: Check whether order can be created for pair (payment, pool) + // TODO(future): If this returns false, we should add a mechanism which checks + // whether `currency` can be swapped into an accepted payment currency. + // + // This requires + // * Querying all accepted payment currencies of an investment + // * Checking whether there are orders from `currency` into an accepted + // payment currency T::Investment::accepted_payment_currency(investment_id, currency) } fn accepted_payout_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { - // FIXME: Check whether order can be created for pair (pool, payment) + // TODO(future): If this returns false, we should add a mechanism which checks + // whether any of the accepted `payout` currencies can be swapped into + // `currency`. + // + // This requires + // * Querying all accepted payout currencies of an investment + // * Checking whether there are orders from an accepted payout currency into + // `currency` T::Investment::accepted_payout_currency(investment_id, currency) } } @@ -553,7 +559,6 @@ impl Pallet { }, )?; CollectedRedemption::::remove(who, investment_id); - Ok(()) } _ => Ok(()), @@ -565,14 +570,12 @@ impl Pallet { match inner_redeem_state { InnerRedeemState::SwapIntoReturnDone { .. } => { RedemptionState::::remove(who, investment_id); - Ok(Some(RedeemState::NoState)) } InnerRedeemState::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } => { let new_state = state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); RedemptionState::::insert(who, investment_id, new_state); - Ok(Some(new_state)) } InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { @@ -586,7 +589,6 @@ impl Pallet { collect_amount, }); RedemptionState::::insert(who, investment_id, new_state); - Ok(Some(new_state)) } InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { @@ -595,7 +597,6 @@ impl Pallet { let new_state = state .swap_inner_state(InnerRedeemState::CollectableRedemption { collect_amount }); RedemptionState::::insert(who, investment_id, new_state); - Ok(Some(new_state)) } _ => Ok(None), @@ -720,39 +721,39 @@ impl Pallet { if swap.amount.is_zero() { return Self::kill_swap_order(who, investment_id); } - if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { - T::TokenSwaps::update_order( - who.clone(), - swap_order_id, - swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), - )?; - TokenSwapReasons::::insert(swap_order_id, reason); - - Ok(()) - } else { - // TODO: How to handle potential failure? - let swap_order_id = T::TokenSwaps::place_order( - who.clone(), - swap.currency_out, - swap.currency_in, - swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), - )?; - TokenSwapOrderIds::::insert(who, investment_id, swap_order_id); - ForeignInvestmentInfo::::insert( - swap_order_id, - ForeignInvestmentInfoOf:: { - owner: who.clone(), - id: investment_id, - }, - ); - TokenSwapReasons::::insert(swap_order_id, reason); - - Ok(()) - } + match TokenSwapOrderIds::::get(who, investment_id) { + Some(swap_order_id) if T::TokenSwaps::is_active(swap_order_id) => { + T::TokenSwaps::update_order( + who.clone(), + swap_order_id, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + )?; + TokenSwapReasons::::insert(swap_order_id, reason); + } + _ => { + // TODO: How to handle potential failure? + let swap_order_id = T::TokenSwaps::place_order( + who.clone(), + swap.currency_out, + swap.currency_in, + swap.amount, + T::DefaultTokenSwapSellPriceLimit::get(), + T::DefaultTokenMinFulfillmentAmount::get(), + )?; + TokenSwapOrderIds::::insert(who, investment_id, swap_order_id); + ForeignInvestmentInfo::::insert( + swap_order_id, + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + }, + ); + TokenSwapReasons::::insert(swap_order_id, reason); + } + }; + Ok(()) } /// Determines the correct amount for a token swap based on the current @@ -919,7 +920,7 @@ impl Pallet { } /// Sends `ExecutedDecreaseInvestHook` notification such that any potential - /// consumer could act upon that, e.g. Liqudity Pools for + /// consumer could act upon that, e.g. Liquidity Pools for /// `ExecutedDecreaseInvestOrder`. #[transactional] fn notify_executed_decrease_invest( @@ -928,28 +929,20 @@ impl Pallet { amount_decreased: T::Balance, return_currency: T::CurrencyId, ) -> DispatchResult { - // TODO(@mustermeiszer): Does this return the entire desired amount or do we - // need to tap into collecting? > Requires artificial collect (which does not - // mutate state) and then look at order id. - // NOTE: We might change amounts to be deltas. - let amount_remaining = T::Investment::investment(who, investment_id)?; - - // TODO(@mustermeiszer): Do we add the active swap amount? T::ExecutedDecreaseInvestHook::notify_status_change( ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, }, - ExecutedDecrease { + ExecutedForeignDecrease { amount_decreased, - amount_remaining, return_currency, }, ) } /// Sends `ExecutedCollectRedeemHook` notification such that any potential - /// consumer could act upon that, e.g. Liqudity Pools for + /// consumer could act upon that, e.g. Liquidity Pools for /// `ExecutedCollectRedeemOrder`. #[transactional] fn notify_executed_collect_redeem( @@ -958,18 +951,15 @@ impl Pallet { currency: T::CurrencyId, collected: CollectedAmount, ) -> DispatchResult { - let amount_remaining = T::Investment::redemption(&who, investment_id)?; - T::ExecutedCollectRedeemHook::notify_status_change( ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, }, - ExecutedCollectRedeem { + ExecutedForeignCollectRedeem { currency, amount_currency_payout: collected.amount_collected, amount_tranche_tokens_payout: collected.amount_payment, - amount_remaining, }, ) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 29c3a601ba..69ec67827f 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -11,6 +11,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use cfg_types::investments::Swap; use frame_support::ensure; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, @@ -32,7 +33,7 @@ use crate::types::{ RedeemingAndCollectableRedemptionAndSwapIntoReturnDone, RedeemingAndSwapIntoReturnDone, SwapIntoReturnDone, }, - RedeemState, RedeemTransition, Swap, + RedeemState, RedeemTransition, }; impl RedeemState diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 3a74d51c46..1c24ef8c5b 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -13,11 +13,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// -pub use pallet::*; - // #[cfg(test)] // mod mock; @@ -28,7 +23,11 @@ pub use pallet::*; // mod benchmarking; // pub mod weights; // pub use weights::*; -use crate::types::Swap; +use cfg_types::investments::Swap; +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// +pub use pallet::*; pub mod impls; pub mod types; @@ -39,14 +38,15 @@ pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentI ::InvestmentId, >; -// TODO: Remove dev_mode before merging -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub mod pallet { use cfg_traits::{ investments::{InvestmentCollector, TrancheCurrency}, StatusNotificationHook, TokenSwaps, }; - use cfg_types::investments::{CollectedAmount, ExecutedCollectRedeem, ExecutedDecrease}; + use cfg_types::investments::{ + CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, + }; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; @@ -67,7 +67,6 @@ pub mod pallet { /// Type representing the weight of this pallet type WeightInfo: frame_system::WeightInfo; - // TODO: Check whether we actually want something like CurrencyBalance /// The source of truth for the balance of accounts type Balance: Parameter + Member @@ -167,15 +166,17 @@ pub mod pallet { OrderId = Self::TokenSwapOrderId, >; + /// The hook type which acts upon a finalized investment decrement. type ExecutedDecreaseInvestHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - Status = ExecutedDecrease, + Status = ExecutedForeignDecrease, Error = DispatchError, >; + /// The hook type which acts upon a finalized redemption collection. type ExecutedCollectRedeemHook: StatusNotificationHook< Id = ForeignInvestmentInfoOf, - Status = ExecutedCollectRedeem, + Status = ExecutedForeignCollectRedeem, Error = DispatchError, >; } @@ -306,6 +307,7 @@ pub mod pallet { } #[pallet::error] + // TODO: Add more errors pub enum Error { /// Failed to retrieve the `InvestmentInfo` from the given /// `TokenSwapOrderId`. diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 0c0415a22d..2e05db82a6 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -11,30 +11,11 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use cfg_types::investments::Swap; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::traits::{EnsureAdd, EnsureSub}; -#[derive( - Clone, - Default, - Copy, - PartialOrd, - Ord, - PartialEq, - Eq, - Debug, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, -)] -pub struct Swap { - pub currency_in: Currency, - pub currency_out: Currency, - pub amount: Balance, -} - /// Reflects the reason for the last token swap update such that it can be /// updated accordingly if the last and current reason mismatch. #[derive( diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 5cf97f8291..4d32eca141 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -16,7 +16,7 @@ use cfg_traits::{ }; use cfg_types::{ domain_address::DomainAddress, - investments::{ExecutedDecrease, ForeignInvestmentInfo}, + investments::{ExecutedForeignDecrease, ForeignInvestmentInfo}, }; use frame_support::{traits::fungibles::Mutate, transactional}; use sp_runtime::{DispatchError, DispatchResult}; @@ -24,10 +24,10 @@ use sp_std::marker::PhantomData; use crate::{pallet::Config, Message, MessageOf, Pallet}; -// TODO: Docs +/// The hook struct which acts upon a finalized investment decrement. pub struct DecreaseInvestOrderHook(PhantomData); -// TODO: Docs +/// The hook struct which acts upon a finalized redemption collection. pub struct CollectRedeemHook(PhantomData); @@ -37,12 +37,12 @@ where { type Error = DispatchError; type Id = ForeignInvestmentInfo; - type Status = ExecutedDecrease; + type Status = ExecutedForeignDecrease; #[transactional] fn notify_status_change( id: ForeignInvestmentInfo, - status: ExecutedDecrease, + status: ExecutedForeignDecrease, ) -> DispatchResult { let ForeignInvestmentInfo { id: investment_id, @@ -60,7 +60,6 @@ where investor: investor.clone().into(), currency, currency_payout: status.amount_decreased, - remaining_invest_order: status.amount_remaining, }; T::OutboundQueue::submit(investor, domain_address.into(), message)?; @@ -75,12 +74,12 @@ where { type Error = DispatchError; type Id = ForeignInvestmentInfo; - type Status = cfg_types::investments::ExecutedCollectRedeem; + type Status = cfg_types::investments::ExecutedForeignCollectRedeem; #[transactional] fn notify_status_change( id: ForeignInvestmentInfo, - status: cfg_types::investments::ExecutedCollectRedeem, + status: cfg_types::investments::ExecutedForeignCollectRedeem, ) -> DispatchResult { let ForeignInvestmentInfo { id: investment_id, @@ -99,7 +98,6 @@ where currency, currency_payout: status.amount_currency_payout, tranche_tokens_payout: status.amount_tranche_tokens_payout, - remaining_invest_order: status.amount_remaining, }; T::OutboundQueue::submit(investor, domain_address.into(), message)?; diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 6c54f963de..4680babfb1 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -16,7 +16,7 @@ use cfg_traits::{ }; use cfg_types::{ domain_address::{Domain, DomainAddress}, - investments::ExecutedCollectInvest, + investments::ExecutedForeignCollectInvest, permissions::{PermissionScope, PoolRole, Role}, }; use frame_support::{ @@ -250,10 +250,9 @@ impl Pallet { ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let ExecutedCollectInvest:: { + let ExecutedForeignCollectInvest:: { amount_currency_payout, amount_tranche_tokens_payout, - amount_remaining, } = T::ForeignInvestment::collect_foreign_investment(&investor, invest_id.clone())?; T::Tokens::transfer( @@ -271,7 +270,6 @@ impl Pallet { currency: currency_index.index, currency_payout: amount_currency_payout, tranche_tokens_payout: amount_tranche_tokens_payout, - remaining_invest_order: amount_remaining, }; T::OutboundQueue::submit(investor, destination, message)?; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 975a363f50..83734d5ad3 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -16,7 +16,7 @@ use core::convert::TryFrom; use cfg_traits::liquidity_pools::{InboundQueue, OutboundQueue}; use cfg_types::{ domain_address::{Domain, DomainAddress}, - investments::ExecutedCollectInvest, + investments::ExecutedForeignCollectInvest, tokens::GeneralCurrencyIndex, }; use cfg_utils::vec_to_fixed_array; @@ -198,7 +198,7 @@ pub mod pallet { CurrencyId = CurrencyIdOf, Error = DispatchError, InvestmentId = ::TrancheCurrency, - CollectInvestResult = ExecutedCollectInvest, + CollectInvestResult = ExecutedForeignCollectInvest, >; /// The source of truth for the transferability of assets via the diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 199212c56c..5dd0d22df0 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -220,8 +220,6 @@ where /// `DecreaseInvestOrder` message, i.e., the amount by which the /// investment order was actually decreased by. currency_payout: Balance, - /// The outstanding order, in `currency` units - remaining_invest_order: Balance, }, /// The message sent back to the domain from which a `DecreaseRedeemOrder` /// message was received, ensuring the correct state update on said domain @@ -256,13 +254,10 @@ where investor: Address, /// The currency in which the investment was realised currency: u128, - /// The amount that was actually collected + /// The amount that was actually collected, in `currency` units currency_payout: Balance, /// The amount of tranche tokens received for the investment made tranche_tokens_payout: Balance, - /// The remaining amount of `currency` the investor still has locked to - /// invest at a later epoch execution - remaining_invest_order: Balance, }, /// The message sent back to the domain from which a `CollectRedeem` message /// has been received, which will ensure the `investor` gets the payout @@ -282,9 +277,6 @@ where currency_payout: Balance, /// How many tranche tokens were actually redeemed tranche_tokens_payout: Balance, - /// The remaining amount of tranche tokens the investor still has locked - /// to redeem at a later epoch execution - remaining_redeem_order: Balance, }, } @@ -522,7 +514,6 @@ impl< investor, currency, currency_payout, - remaining_invest_order, } => encoded_message( self.call_type(), vec![ @@ -531,7 +522,6 @@ impl< investor.to_vec(), encode_be(currency), encode_be(currency_payout), - encode_be(remaining_invest_order), ], ), Message::ExecutedDecreaseRedeemOrder { @@ -557,7 +547,6 @@ impl< currency, currency_payout, tranche_tokens_payout, - remaining_invest_order, } => encoded_message( self.call_type(), vec![ @@ -567,7 +556,6 @@ impl< encode_be(currency), encode_be(currency_payout), encode_be(tranche_tokens_payout), - encode_be(remaining_invest_order), ], ), Message::ExecutedCollectRedeem { @@ -577,7 +565,6 @@ impl< currency, currency_payout, tranche_tokens_payout, - remaining_redeem_order, } => encoded_message( self.call_type(), vec![ @@ -587,7 +574,6 @@ impl< encode_be(currency), encode_be(currency_payout), encode_be(tranche_tokens_payout), - encode_be(remaining_redeem_order), ], ), } @@ -674,7 +660,7 @@ impl< pool_id: decode_be_bytes::<8, _, _>(input)?, tranche_id: decode::<16, _, _>(input)?, investor: decode::<32, _, _>(input)?, - currency: decode_be_bytes::<8, _, _>(input)?, + currency: decode_be_bytes::<16, _, _>(input)?, }), 14 => Ok(Self::CollectRedeem { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -688,7 +674,6 @@ impl< investor: decode::<32, _, _>(input)?, currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, - remaining_invest_order: decode_be_bytes::<16, _, _>(input)?, }), 16 => Ok(Self::ExecutedDecreaseRedeemOrder { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -704,7 +689,6 @@ impl< currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, - remaining_invest_order: decode_be_bytes::<16, _, _>(input)?, }), 18 => Ok(Self::ExecutedCollectRedeem { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -713,7 +697,6 @@ impl< currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, - remaining_redeem_order: decode_be_bytes::<16, _, _>(input)?, }), _ => Err(codec::Error::from( "Unsupported decoding for this Message variant", @@ -1011,7 +994,7 @@ mod tests { investor: default_address_32(), currency: TOKEN_ID, }, - "0d0000000000000001811acd5b3f17c06841c7e41e9e04cb1b4564564564564564564564564564564564564564564564564564564564564564", + "0d0000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b", ) } @@ -1037,9 +1020,8 @@ mod tests { investor: vec_to_fixed_array(default_address_20().to_vec()), currency: TOKEN_ID, currency_payout: AMOUNT / 2, - remaining_invest_order: AMOUNT * 2 }, - "0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e640669720000000000000000a56fa5b99019a5c8000000", + "0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", ) } @@ -1053,7 +1035,7 @@ mod tests { currency: TOKEN_ID, tranche_tokens_payout: AMOUNT / 2, }, - "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e640669720000000000000000a56fa5b99019a5c8000000", + "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", ) } @@ -1067,9 +1049,8 @@ mod tests { currency: TOKEN_ID, currency_payout: AMOUNT, tranche_tokens_payout: AMOUNT / 2, - remaining_invest_order: AMOUNT * 3, }, - "110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e640669720000000000000000f8277896582678ac000000", + "110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", ) } @@ -1083,9 +1064,8 @@ mod tests { currency: TOKEN_ID, currency_payout: AMOUNT, tranche_tokens_payout: AMOUNT / 2, - remaining_redeem_order: AMOUNT * 3, }, - "120000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e640669720000000000000000f8277896582678ac000000", + "120000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", ) } @@ -1098,8 +1078,12 @@ mod tests { let encoded = msg.serialize(); assert_eq!(hex::encode(encoded.clone()), expected_hex); - let decoded: Message = - Message::deserialize(&mut hex::decode(expected_hex).expect("").as_slice()).expect(""); + let decoded: Message = Message::deserialize( + &mut hex::decode(expected_hex) + .expect("Decode should work") + .as_slice(), + ) + .expect("Deserialization should work"); assert_eq!(msg, decoded); } From 845c1b561036e8d62208c30dc19306f0e01ede85 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 11:26:01 +0200 Subject: [PATCH 20/96] feat: add FulfilledOrderHook to Orderbook --- pallets/order-book/src/lib.rs | 23 ++++++++++++++++++++--- runtime/development/src/lib.rs | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index 336d222d5f..836a63c681 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -39,8 +39,8 @@ pub mod pallet { use core::fmt::Debug; - use cfg_traits::fees::Fees; - use cfg_types::tokens::CustomMetadata; + use cfg_traits::{fees::Fees, StatusNotificationHook}; + use cfg_types::{investments::Swap, tokens::CustomMetadata}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ pallet_prelude::{DispatchResult, Member, StorageDoubleMap, StorageValue, *}, @@ -169,6 +169,13 @@ pub mod pallet { #[pallet::constant] type OrderPairVecSize: Get; + /// The hook which acts upon a (partially) fulfilled order + type FulfilledOrderHook: StatusNotificationHook< + Id = Self::OrderIdNonce, + Status = Swap, + Error = DispatchError, + >; + /// Type for pallet weights type Weights: WeightInfo; } @@ -394,6 +401,16 @@ pub mod pallet { sell_amount, )?; Self::remove_order(order.order_id)?; + + T::FulfilledOrderHook::notify_status_change( + order_id, + Swap { + amount: order.buy_amount, + currency_in: order.asset_in_id, + currency_out: order.asset_out_id, + }, + )?; + Self::deposit_event(Event::OrderFulfillment { order_id, placing_account: order.placing_account, @@ -463,7 +480,7 @@ pub mod pallet { type OrderId = T::OrderIdNonce; /// Creates an order. - /// Verify funds available in, and reserve for both chains fee currency + /// Verify funds available in, and reserve for both chains fee currency /// for storage fee, and amount of outgoing currency as determined by /// the buy amount and price. fn place_order( diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 3f5c80cf7b..29822fcd36 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1873,6 +1873,7 @@ impl pallet_order_book::Config for Runtime { type FeeCurrencyId = NativeToken; type Fees = Fees; type ForeignCurrencyBalance = Balance; + type FulfilledOrderHook = ForeignInvestments; type OrderFeeKey = OrderBookCreationFeeKey; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; From 267885189ae8880283d30acdd2afee1fd790f8de Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 12:00:09 +0200 Subject: [PATCH 21/96] fix: use remaining collectable redemption amount --- libs/traits/src/investments.rs | 7 +- libs/types/src/investments.rs | 29 ++- pallets/foreign-investments/src/impls/mod.rs | 32 +-- .../foreign-investments/src/impls/redeem.rs | 199 +++++++++++++----- pallets/foreign-investments/src/lib.rs | 10 +- pallets/foreign-investments/src/types.rs | 2 +- pallets/investments/src/lib.rs | 22 +- 7 files changed, 205 insertions(+), 96 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 7cc5eae6ac..4741668eda 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -91,7 +91,8 @@ pub trait Investment { pub trait InvestmentCollector { type Error: Debug; type InvestmentId; - type Result: Debug; + type InvestResult: Debug; + type RedeemResult: Debug; /// Collect the results of a user's invest orders for the given /// investment. If any amounts are not fulfilled they are directly @@ -99,7 +100,7 @@ pub trait InvestmentCollector { fn collect_investment( who: AccountId, investment_id: Self::InvestmentId, - ) -> Result; + ) -> Result; /// Collect the results of a users redeem orders for the given /// investment. If any amounts are not fulfilled they are directly @@ -107,7 +108,7 @@ pub trait InvestmentCollector { fn collect_redemption( who: AccountId, investment_id: Self::InvestmentId, - ) -> Result; + ) -> Result; } /// A trait, when implemented must take care of diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 891dbb3264..afc057e890 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -136,21 +136,32 @@ impl RedeemCollection { } } -/// The collected investment/redemption amount for an account +/// The collected investment amounts for an account #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct CollectedAmount { - /// The amount which was was collected - /// * If investment: Tranche tokens - /// * If redemption: Payment currency +pub struct CollectedInvestment { + /// The amount of tranche tokens which was was collected pub amount_collected: Balance, - /// The amount which invested and converted during processing based on the - /// fulfillment price(s) - /// * If investment: Payment currency - /// * If redemption: Tranche tokens + /// The previously invested amount of payment currency which was converted + /// during processing based on the fulfillment price(s) pub amount_payment: Balance, } +/// The collected redemption amounts for an account +#[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectedRedemption { + /// The amount of payment currency which was was collected + pub amount_collected: Balance, + + /// The previously invested amount of tranche tokens which was converted + /// during processing based on the fulfillment price(s) + pub amount_payment: Balance, + + /// The remaining collectable amount which was already processed during + /// epoch execution + pub amount_remaining_collectable: Balance, +} + /// A representation of an investment identifier and the corresponding owner. /// /// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 3000c88317..d2f023105a 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -16,7 +16,7 @@ use cfg_traits::{ StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, + CollectedInvestment, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, Swap, }; use frame_support::{traits::Get, transactional}; @@ -30,7 +30,7 @@ use crate::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, }, - CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, + CollectedRedemptions, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, }; @@ -153,7 +153,7 @@ impl ForeignInvestment for Pallet { ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is // independent of the current `InvestState` - let CollectedAmount:: { + let CollectedInvestment:: { amount_collected, amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; @@ -173,10 +173,11 @@ impl ForeignInvestment for Pallet { pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; - CollectedRedemption::::try_mutate(who, investment_id, |collected_redemption| { + CollectedRedemptions::::try_mutate(who, investment_id, |collected_redemption| { collected_redemption .amount_collected .ensure_add_assign(collected.amount_collected)?; + // TODO: We only need this at a later stage collected_redemption .amount_payment .ensure_add_assign(collected.amount_payment)?; @@ -186,11 +187,14 @@ impl ForeignInvestment for Pallet { // Transition state to initiate swap from pool to return currency let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = pre_state.transition(RedeemTransition::Collect(SwapOf:: { - amount: collected.amount_collected, - currency_in: return_currency, - currency_out: pool_currency, - }))?; + let post_state = pre_state.transition(RedeemTransition::Collect( + SwapOf:: { + amount: collected.amount_collected, + currency_in: return_currency, + currency_out: pool_currency, + }, + collected.amount_remaining_collectable, + ))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -537,9 +541,9 @@ impl Pallet { inner_redeem_state: InnerRedeemState, ) -> Result>, DispatchError> { // TODO: Should just be amount and maybe factor in the remaining amount as well - let collected_redemption = CollectedRedemption::::get(who, investment_id); + let collected_redemption = CollectedRedemptions::::get(who, investment_id); - // Send notification and kill `CollectedRedemption` iff the state includes + // Send notification and kill `CollectedRedemptions` iff the state includes // `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` match inner_redeem_state { InnerRedeemState::SwapIntoReturnDone { done_swap, .. } @@ -553,12 +557,12 @@ impl Pallet { who, investment_id, done_swap.currency_in, - CollectedAmount { + CollectedInvestment { amount_collected: done_swap.amount, amount_payment: collected_redemption.amount_payment, }, )?; - CollectedRedemption::::remove(who, investment_id); + CollectedRedemptions::::remove(who, investment_id); Ok(()) } _ => Ok(()), @@ -949,7 +953,7 @@ impl Pallet { who: &T::AccountId, investment_id: T::InvestmentId, currency: T::CurrencyId, - collected: CollectedAmount, + collected: CollectedInvestment, ) -> DispatchResult { T::ExecutedCollectRedeemHook::notify_status_change( ForeignInvestmentInfoOf:: { diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 69ec67827f..8f2d742b70 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -56,7 +56,9 @@ where RedeemTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(&self, swap) } - RedeemTransition::Collect(swap) => Self::handle_collect(&self, swap), + RedeemTransition::Collect(swap, remaining_collectable) => { + Self::handle_collect(&self, swap, remaining_collectable) + } } } @@ -573,6 +575,7 @@ where fn transition_collect( &self, collected_swap: Swap, + remaining_collectable: Balance, ) -> Result { ensure!( self.get_active_swap() @@ -590,66 +593,141 @@ where RedeemingAndActiveSwapIntoReturnCurrency { .. } | RedeemingAndSwapIntoReturnDone { .. } | RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), - // TODO: Probably just ignore `collect_amount` - CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { - swap: collected_swap, - }), - RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: collected_swap, - }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: Swap { + CollectableRedemption { .. } => { + if remaining_collectable.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: collected_swap, + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + collect_amount: remaining_collectable, + swap: collected_swap, + }) + } + }, + RedeemingAndCollectableRedemption { redeem_amount, .. } => { + if remaining_collectable.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: collected_swap, + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: collected_swap, + collect_amount: remaining_collectable, + }) + } + }, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap, .. } => { + let new_swap = Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: new_swap + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: new_swap, + collect_amount: remaining_collectable + }) } - }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: Swap { - amount: collected_swap.amount, - ..collected_swap - }, - done_amount: done_swap.amount - }) }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - done_amount - }) + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap, .. } => { + let new_swap = Swap { + amount: collected_swap.amount, + ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: new_swap, + done_amount: done_swap.amount + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: new_swap, + done_amount: done_swap.amount, + collect_amount: remaining_collectable + }) + } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { - Ok(Self::ActiveSwapIntoReturnCurrency { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - } - }) + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount, .. } => { + let new_swap = Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: new_swap, + done_amount + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: new_swap, + done_amount, + collect_amount: remaining_collectable + }) + } + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => { + let new_swap = Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: new_swap + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + swap: new_swap, + collect_amount: remaining_collectable + }) + } }, CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - amount: collected_swap.amount, - ..collected_swap - }, - done_amount: done_swap.amount, - }) + let new_swap = Swap { + amount: collected_swap.amount, + ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: new_swap, + done_amount: done_swap.amount, + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: new_swap, + done_amount: done_swap.amount, + collect_amount: remaining_collectable + }) + } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - done_amount - }) + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount , .. } => { + let new_swap = Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + if remaining_collectable.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: new_swap, + done_amount + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: new_swap, + done_amount, + collect_amount: remaining_collectable + }) + } }, } } @@ -802,14 +880,21 @@ where /// Throws if the state does not allow for collection or the the inner state /// includes an active/done swap with mismatching currencies to the provided /// ones. - fn handle_collect(&self, swap: Swap) -> Result { + fn handle_collect( + &self, + swap: Swap, + remaining_collectable: Balance, + ) -> Result { match self { RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( "Invalid redeem state when transitioning collect", )), - RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( - Self::swap_inner_state(&self, inner.transition_collect(swap)?), - ), + RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => { + Ok(Self::swap_inner_state( + &self, + inner.transition_collect(swap, remaining_collectable)?, + )) + } } } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 1c24ef8c5b..42a227b28b 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -45,7 +45,8 @@ pub mod pallet { StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, + CollectedInvestment, CollectedRedemption, ExecutedForeignCollectRedeem, + ExecutedForeignDecrease, }; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; @@ -124,7 +125,8 @@ pub mod pallet { Self::AccountId, Error = DispatchError, InvestmentId = Self::InvestmentId, - Result = CollectedAmount, + InvestResult = CollectedInvestment, + RedeemResult = CollectedRedemption, >; /// The default sell price limit for token swaps which defines the @@ -256,13 +258,13 @@ pub mod pallet { /// in pool currency and ends with having swapped the entire amount to /// return currency. #[pallet::storage] - pub(super) type CollectedRedemption = StorageDoubleMap< + pub(super) type CollectedRedemptions = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, - CollectedAmount, + CollectedInvestment, ValueQuery, >; diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 2e05db82a6..d8b27efeb1 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -325,5 +325,5 @@ pub enum RedeemTransition< IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), - Collect(Swap), + Collect(Swap, Balance), } diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 4f9d767866..407b2dc577 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -23,7 +23,10 @@ use cfg_traits::{ }; use cfg_types::{ fixed_point::FixedPointNumberExtension, - investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection}, + investments::{ + CollectedInvestment, CollectedRedemption, InvestCollection, InvestmentAccount, + RedeemCollection, + }, orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ @@ -634,7 +637,7 @@ where pub(crate) fn do_collect_invest( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedInvestment, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; InvestOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -713,7 +716,7 @@ where }, ); - let collected_investment = CollectedAmount { + let collected_investment = CollectedInvestment { amount_collected: collection.payout_investment_invest, amount_payment, }; @@ -739,7 +742,7 @@ where pub(crate) fn do_collect_redeem( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedRedemption, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; RedeemOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -774,6 +777,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() + // TODO: Check in foreign if its okay to return 0 remaining return Ok((Default::default(), ().into())); } @@ -826,9 +830,10 @@ where }, ); - let collected_redemption = CollectedAmount { + let collected_redemption = CollectedRedemption { amount_collected: collection.payout_investment_redeem, amount_payment, + amount_remaining_collectable: collection.remaining_investment_redeem, }; Self::deposit_event(Event::RedeemOrdersCollected { @@ -1436,14 +1441,15 @@ where InvestmentProperties>, { type Error = DispatchError; + type InvestResult = CollectedInvestment; type InvestmentId = T::InvestmentId; - type Result = CollectedAmount; + type RedeemResult = CollectedRedemption; // TODO: Write unit test in investments to test this fn collect_investment( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { Pallet::::do_collect_invest(who, investment_id) .map_err(|e| e.error) .map(|(collected_amount, _)| collected_amount) @@ -1453,7 +1459,7 @@ where fn collect_redemption( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { Pallet::::do_collect_redeem(who, investment_id) .map_err(|e| e.error) .map(|(collected_amount, _)| collected_amount) From 48024e3d42ec14c58550932b0a7ee9c97a204b35 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 14:31:50 +0200 Subject: [PATCH 22/96] Revert "fix: use remaining collectable redemption amount" This reverts commit 267885189ae8880283d30acdd2afee1fd790f8de. --- libs/traits/src/investments.rs | 7 +- libs/types/src/investments.rs | 29 +-- pallets/foreign-investments/src/impls/mod.rs | 32 ++- .../foreign-investments/src/impls/redeem.rs | 199 +++++------------- pallets/foreign-investments/src/lib.rs | 10 +- pallets/foreign-investments/src/types.rs | 2 +- pallets/investments/src/lib.rs | 22 +- 7 files changed, 96 insertions(+), 205 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 4741668eda..7cc5eae6ac 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -91,8 +91,7 @@ pub trait Investment { pub trait InvestmentCollector { type Error: Debug; type InvestmentId; - type InvestResult: Debug; - type RedeemResult: Debug; + type Result: Debug; /// Collect the results of a user's invest orders for the given /// investment. If any amounts are not fulfilled they are directly @@ -100,7 +99,7 @@ pub trait InvestmentCollector { fn collect_investment( who: AccountId, investment_id: Self::InvestmentId, - ) -> Result; + ) -> Result; /// Collect the results of a users redeem orders for the given /// investment. If any amounts are not fulfilled they are directly @@ -108,7 +107,7 @@ pub trait InvestmentCollector { fn collect_redemption( who: AccountId, investment_id: Self::InvestmentId, - ) -> Result; + ) -> Result; } /// A trait, when implemented must take care of diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index afc057e890..891dbb3264 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -136,32 +136,21 @@ impl RedeemCollection { } } -/// The collected investment amounts for an account +/// The collected investment/redemption amount for an account #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct CollectedInvestment { - /// The amount of tranche tokens which was was collected +pub struct CollectedAmount { + /// The amount which was was collected + /// * If investment: Tranche tokens + /// * If redemption: Payment currency pub amount_collected: Balance, - /// The previously invested amount of payment currency which was converted - /// during processing based on the fulfillment price(s) + /// The amount which invested and converted during processing based on the + /// fulfillment price(s) + /// * If investment: Payment currency + /// * If redemption: Tranche tokens pub amount_payment: Balance, } -/// The collected redemption amounts for an account -#[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct CollectedRedemption { - /// The amount of payment currency which was was collected - pub amount_collected: Balance, - - /// The previously invested amount of tranche tokens which was converted - /// during processing based on the fulfillment price(s) - pub amount_payment: Balance, - - /// The remaining collectable amount which was already processed during - /// epoch execution - pub amount_remaining_collectable: Balance, -} - /// A representation of an investment identifier and the corresponding owner. /// /// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index d2f023105a..3000c88317 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -16,7 +16,7 @@ use cfg_traits::{ StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedInvestment, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, + CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, Swap, }; use frame_support::{traits::Get, transactional}; @@ -30,7 +30,7 @@ use crate::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, }, - CollectedRedemptions, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, + CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, }; @@ -153,7 +153,7 @@ impl ForeignInvestment for Pallet { ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is // independent of the current `InvestState` - let CollectedInvestment:: { + let CollectedAmount:: { amount_collected, amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; @@ -173,11 +173,10 @@ impl ForeignInvestment for Pallet { pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; - CollectedRedemptions::::try_mutate(who, investment_id, |collected_redemption| { + CollectedRedemption::::try_mutate(who, investment_id, |collected_redemption| { collected_redemption .amount_collected .ensure_add_assign(collected.amount_collected)?; - // TODO: We only need this at a later stage collected_redemption .amount_payment .ensure_add_assign(collected.amount_payment)?; @@ -187,14 +186,11 @@ impl ForeignInvestment for Pallet { // Transition state to initiate swap from pool to return currency let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = pre_state.transition(RedeemTransition::Collect( - SwapOf:: { - amount: collected.amount_collected, - currency_in: return_currency, - currency_out: pool_currency, - }, - collected.amount_remaining_collectable, - ))?; + let post_state = pre_state.transition(RedeemTransition::Collect(SwapOf:: { + amount: collected.amount_collected, + currency_in: return_currency, + currency_out: pool_currency, + }))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -541,9 +537,9 @@ impl Pallet { inner_redeem_state: InnerRedeemState, ) -> Result>, DispatchError> { // TODO: Should just be amount and maybe factor in the remaining amount as well - let collected_redemption = CollectedRedemptions::::get(who, investment_id); + let collected_redemption = CollectedRedemption::::get(who, investment_id); - // Send notification and kill `CollectedRedemptions` iff the state includes + // Send notification and kill `CollectedRedemption` iff the state includes // `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` match inner_redeem_state { InnerRedeemState::SwapIntoReturnDone { done_swap, .. } @@ -557,12 +553,12 @@ impl Pallet { who, investment_id, done_swap.currency_in, - CollectedInvestment { + CollectedAmount { amount_collected: done_swap.amount, amount_payment: collected_redemption.amount_payment, }, )?; - CollectedRedemptions::::remove(who, investment_id); + CollectedRedemption::::remove(who, investment_id); Ok(()) } _ => Ok(()), @@ -953,7 +949,7 @@ impl Pallet { who: &T::AccountId, investment_id: T::InvestmentId, currency: T::CurrencyId, - collected: CollectedInvestment, + collected: CollectedAmount, ) -> DispatchResult { T::ExecutedCollectRedeemHook::notify_status_change( ForeignInvestmentInfoOf:: { diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 8f2d742b70..69ec67827f 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -56,9 +56,7 @@ where RedeemTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(&self, swap) } - RedeemTransition::Collect(swap, remaining_collectable) => { - Self::handle_collect(&self, swap, remaining_collectable) - } + RedeemTransition::Collect(swap) => Self::handle_collect(&self, swap), } } @@ -575,7 +573,6 @@ where fn transition_collect( &self, collected_swap: Swap, - remaining_collectable: Balance, ) -> Result { ensure!( self.get_active_swap() @@ -593,141 +590,66 @@ where RedeemingAndActiveSwapIntoReturnCurrency { .. } | RedeemingAndSwapIntoReturnDone { .. } | RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), - CollectableRedemption { .. } => { - if remaining_collectable.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrency { - swap: collected_swap, - }) - } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { - collect_amount: remaining_collectable, - swap: collected_swap, - }) - } - }, - RedeemingAndCollectableRedemption { redeem_amount, .. } => { - if remaining_collectable.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: collected_swap, - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: collected_swap, - collect_amount: remaining_collectable, - }) - } - }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap, .. } => { - let new_swap = Swap { + // TODO: Probably just ignore `collect_amount` + CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { + swap: collected_swap, + }), + RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: collected_swap, + }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: new_swap - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: new_swap, - collect_amount: remaining_collectable - }) - } - }, - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap, .. } => { - let new_swap = Swap { - amount: collected_swap.amount, - ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: new_swap, - done_amount: done_swap.amount - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: new_swap, - done_amount: done_swap.amount, - collect_amount: remaining_collectable - }) } + }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: collected_swap.amount, + ..collected_swap + }, + done_amount: done_swap.amount + }) }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount, .. } => { - let new_swap = Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: new_swap, - done_amount - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: new_swap, - done_amount, - collect_amount: remaining_collectable - }) - } + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + done_amount + }) }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => { - let new_swap = Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrency { - swap: new_swap - }) - } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { - swap: new_swap, - collect_amount: remaining_collectable - }) - } + CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + } + }) }, CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { - let new_swap = Swap { - amount: collected_swap.amount, - ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: new_swap, - done_amount: done_swap.amount, - }) - } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: new_swap, - done_amount: done_swap.amount, - collect_amount: remaining_collectable - }) - } + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: collected_swap.amount, + ..collected_swap + }, + done_amount: done_swap.amount, + }) }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount , .. } => { - let new_swap = Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }; - if remaining_collectable.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: new_swap, - done_amount - }) - } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: new_swap, - done_amount, - collect_amount: remaining_collectable - }) - } + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + done_amount + }) }, } } @@ -880,21 +802,14 @@ where /// Throws if the state does not allow for collection or the the inner state /// includes an active/done swap with mismatching currencies to the provided /// ones. - fn handle_collect( - &self, - swap: Swap, - remaining_collectable: Balance, - ) -> Result { + fn handle_collect(&self, swap: Swap) -> Result { match self { RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( "Invalid redeem state when transitioning collect", )), - RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => { - Ok(Self::swap_inner_state( - &self, - inner.transition_collect(swap, remaining_collectable)?, - )) - } + RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( + Self::swap_inner_state(&self, inner.transition_collect(swap)?), + ), } } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 42a227b28b..1c24ef8c5b 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -45,8 +45,7 @@ pub mod pallet { StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedInvestment, CollectedRedemption, ExecutedForeignCollectRedeem, - ExecutedForeignDecrease, + CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, }; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; @@ -125,8 +124,7 @@ pub mod pallet { Self::AccountId, Error = DispatchError, InvestmentId = Self::InvestmentId, - InvestResult = CollectedInvestment, - RedeemResult = CollectedRedemption, + Result = CollectedAmount, >; /// The default sell price limit for token swaps which defines the @@ -258,13 +256,13 @@ pub mod pallet { /// in pool currency and ends with having swapped the entire amount to /// return currency. #[pallet::storage] - pub(super) type CollectedRedemptions = StorageDoubleMap< + pub(super) type CollectedRedemption = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, - CollectedInvestment, + CollectedAmount, ValueQuery, >; diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index d8b27efeb1..2e05db82a6 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -325,5 +325,5 @@ pub enum RedeemTransition< IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), - Collect(Swap, Balance), + Collect(Swap), } diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 407b2dc577..4f9d767866 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -23,10 +23,7 @@ use cfg_traits::{ }; use cfg_types::{ fixed_point::FixedPointNumberExtension, - investments::{ - CollectedInvestment, CollectedRedemption, InvestCollection, InvestmentAccount, - RedeemCollection, - }, + investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection}, orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ @@ -637,7 +634,7 @@ where pub(crate) fn do_collect_invest( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedInvestment, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; InvestOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -716,7 +713,7 @@ where }, ); - let collected_investment = CollectedInvestment { + let collected_investment = CollectedAmount { amount_collected: collection.payout_investment_invest, amount_payment, }; @@ -742,7 +739,7 @@ where pub(crate) fn do_collect_redeem( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedRedemption, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; RedeemOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -777,7 +774,6 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() - // TODO: Check in foreign if its okay to return 0 remaining return Ok((Default::default(), ().into())); } @@ -830,10 +826,9 @@ where }, ); - let collected_redemption = CollectedRedemption { + let collected_redemption = CollectedAmount { amount_collected: collection.payout_investment_redeem, amount_payment, - amount_remaining_collectable: collection.remaining_investment_redeem, }; Self::deposit_event(Event::RedeemOrdersCollected { @@ -1441,15 +1436,14 @@ where InvestmentProperties>, { type Error = DispatchError; - type InvestResult = CollectedInvestment; type InvestmentId = T::InvestmentId; - type RedeemResult = CollectedRedemption; + type Result = CollectedAmount; // TODO: Write unit test in investments to test this fn collect_investment( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { Pallet::::do_collect_invest(who, investment_id) .map_err(|e| e.error) .map(|(collected_amount, _)| collected_amount) @@ -1459,7 +1453,7 @@ where fn collect_redemption( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { Pallet::::do_collect_redeem(who, investment_id) .map_err(|e| e.error) .map(|(collected_amount, _)| collected_amount) From 0b2fdf71a880ce7de2e264dee8368e981cff7fdc Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 14:39:14 +0200 Subject: [PATCH 23/96] refactor: remove collect_amount from InnerRedeemState --- pallets/foreign-investments/src/impls/mod.rs | 11 +-- .../foreign-investments/src/impls/redeem.rs | 82 +++++++++---------- pallets/foreign-investments/src/types.rs | 21 +---- 3 files changed, 44 insertions(+), 70 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 3000c88317..877db54aaa 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -417,7 +417,7 @@ impl Pallet { match inner { InnerRedeemState::Redeeming { .. } | InnerRedeemState::RedeemingAndCollectableRedemption { .. } | - InnerRedeemState::CollectableRedemption { .. } => { + InnerRedeemState::CollectableRedemption => { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), None)) }, @@ -580,22 +580,17 @@ impl Pallet { } InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, - collect_amount, .. } => { let new_state = state.swap_inner_state(InnerRedeemState::RedeemingAndCollectableRedemption { redeem_amount, - collect_amount, }); RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } - InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { - collect_amount, .. - } => { - let new_state = state - .swap_inner_state(InnerRedeemState::CollectableRedemption { collect_amount }); + InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { .. } => { + let new_state = state.swap_inner_state(InnerRedeemState::CollectableRedemption); RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 69ec67827f..516b569327 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -303,13 +303,12 @@ where ) } }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { if amount == swap.amount { Ok( Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: *swap, redeem_amount: *redeem_amount, - collect_amount: *collect_amount, } ) } else { @@ -321,12 +320,11 @@ where }, done_amount: amount, redeem_amount: *redeem_amount, - collect_amount: *collect_amount, } ) } }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { @@ -337,7 +335,6 @@ where ..*swap }, redeem_amount: *redeem_amount, - collect_amount: *collect_amount, } ) } else { @@ -349,17 +346,15 @@ where }, done_amount, redeem_amount: *redeem_amount, - collect_amount: *collect_amount, } ) } }, - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { if amount == swap.amount { Ok( Self::CollectableRedemptionAndSwapIntoReturnDone { done_swap: *swap, - collect_amount: *collect_amount, } ) } else { @@ -370,12 +365,11 @@ where ..*swap }, done_amount: amount, - collect_amount: *collect_amount, } ) } }, - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { @@ -385,7 +379,6 @@ where amount: done_amount, ..*swap }, - collect_amount: *collect_amount, } ) } else { @@ -396,7 +389,6 @@ where ..*swap }, done_amount, - collect_amount: *collect_amount, } ) } @@ -427,13 +419,13 @@ where if amount.is_zero() { match *self { Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), - RedeemingAndCollectableRedemption { collect_amount, .. } => Ok(CollectableRedemption { collect_amount }), + RedeemingAndCollectableRedemption { .. } => Ok(CollectableRedemption), RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(ActiveSwapIntoReturnCurrency { swap }), RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(SwapIntoReturnDone { done_swap }), RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), // Throw for states without `Redeeming` // TODO: Create pallet error NotRedeeming inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), @@ -443,20 +435,20 @@ where else { match *self { Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount, collect_amount }), + RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, collect_amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, collect_amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, collect_amount, swap, done_amount }), - CollectableRedemption { collect_amount } => Ok(RedeemingAndCollectableRedemption { collect_amount, redeem_amount: amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), SwapIntoReturnDone { done_swap } => Ok(RedeemingAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap, redeem_amount: amount }), - CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), + CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), } } } @@ -493,7 +485,7 @@ where // the swap match *self { Redeeming { .. } | - CollectableRedemption { .. } | + CollectableRedemption | RedeemingAndCollectableRedemption { .. } | SwapIntoReturnDone { .. } | RedeemingAndSwapIntoReturnDone { .. } | @@ -529,34 +521,34 @@ where Ok(RedeemingAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount, collect_amount }) + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, redeem_amount, collect_amount }) + Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, redeem_amount }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount, collect_amount }) + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount, collect_amount }) + Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, collect_amount }) + Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) } else { - Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, collect_amount }) + Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: swap }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, collect_amount }) + Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) } else { - Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, collect_amount }) + Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) } }, } @@ -591,21 +583,21 @@ where RedeemingAndSwapIntoReturnDone { .. } | RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), // TODO: Probably just ignore `collect_amount` - CollectableRedemption { collect_amount } => Ok(Self::ActiveSwapIntoReturnCurrency { + CollectableRedemption => Ok(Self::ActiveSwapIntoReturnCurrency { swap: collected_swap, }), - RedeemingAndCollectableRedemption { redeem_amount, collect_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + RedeemingAndCollectableRedemption { redeem_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap: collected_swap, }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, collect_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap } }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, collect_amount, done_swap } => { + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => { Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap: Swap { @@ -615,7 +607,7 @@ where done_amount: done_swap.amount }) }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, collect_amount, swap, done_amount } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap: Swap { @@ -625,7 +617,7 @@ where done_amount }) }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { collect_amount, swap } => { + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { Ok(Self::ActiveSwapIntoReturnCurrency { swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, @@ -633,7 +625,7 @@ where } }) }, - CollectableRedemptionAndSwapIntoReturnDone { collect_amount, done_swap } => { + CollectableRedemptionAndSwapIntoReturnDone { done_swap } => { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: collected_swap.amount, @@ -642,7 +634,7 @@ where done_amount: done_swap.amount, }) }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { collect_amount, swap, done_amount } => { + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 2e05db82a6..4316574a33 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -203,13 +203,10 @@ pub enum InnerRedeemState< Redeeming { redeem_amount: Balance }, /// The redemption was fully processed and must be collected before it can /// be transferred back. - CollectableRedemption { collect_amount: Balance }, + CollectableRedemption, /// The redemption was partially processed and is split into a pending /// redemption and a collectable amount. - RedeemingAndCollectableRedemption { - redeem_amount: Balance, - collect_amount: Balance, - }, + RedeemingAndCollectableRedemption { redeem_amount: Balance }, /// The redemption was fully processed and collected and is currently /// swapping into the return currency. ActiveSwapIntoReturnCurrency { swap: Swap }, @@ -261,7 +258,6 @@ pub enum InnerRedeemState< /// result of processing and collecting beforehand. RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: Balance, - collect_amount: Balance, swap: Swap, }, /// The redemption is split into three parts: @@ -271,7 +267,6 @@ pub enum InnerRedeemState< /// currency as a result of processing and collecting beforehand. RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: Balance, - collect_amount: Balance, done_swap: Swap, }, /// The redemption is split into four parts: @@ -282,7 +277,6 @@ pub enum InnerRedeemState< /// * The remainder was already swapped back. RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: Balance, - collect_amount: Balance, swap: Swap, done_amount: Balance, }, @@ -290,25 +284,18 @@ pub enum InnerRedeemState< /// * One part is waiting to be collected. /// * The remainder is swapping back into the return currency as a /// result of processing and collecting beforehand. - CollectableRedemptionAndActiveSwapIntoReturnCurrency { - collect_amount: Balance, - swap: Swap, - }, + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap: Swap }, /// The redemption is split into two parts: /// * One part is waiting to be collected. /// * The remainder was successfully swapped back into the return /// currency as a result of processing and collecting beforehand. - CollectableRedemptionAndSwapIntoReturnDone { - collect_amount: Balance, - done_swap: Swap, - }, + CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap }, /// The redemption is split into three parts: /// * One part is waiting to be collected. /// * The second is swapping back into the return currency as a result of /// processing and collecting beforehand /// * The remainder was already swapped back. CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - collect_amount: Balance, swap: Swap, done_amount: Balance, }, From d896e00b69af589be13f336cace8c1a3e7a4507f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 16:14:46 +0200 Subject: [PATCH 24/96] fix: collect redemption --- pallets/foreign-investments/src/impls/mod.rs | 28 +- .../foreign-investments/src/impls/redeem.rs | 263 ++++++++++++++---- pallets/foreign-investments/src/lib.rs | 12 +- 3 files changed, 223 insertions(+), 80 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 877db54aaa..7224726125 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -30,8 +30,9 @@ use crate::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, }, - CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, - InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, TokenSwapReasons, + CollectedRedemptionTrancheTokens, Config, Error, Event, ForeignInvestmentInfo, + ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, + TokenSwapReasons, }; mod invest; @@ -173,13 +174,8 @@ impl ForeignInvestment for Pallet { pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; - CollectedRedemption::::try_mutate(who, investment_id, |collected_redemption| { - collected_redemption - .amount_collected - .ensure_add_assign(collected.amount_collected)?; - collected_redemption - .amount_payment - .ensure_add_assign(collected.amount_payment)?; + CollectedRedemptionTrancheTokens::::try_mutate(who, investment_id, |amount| { + amount.ensure_add_assign(collected.amount_payment)?; Ok::<(), DispatchError>(()) })?; @@ -536,11 +532,11 @@ impl Pallet { state: RedeemState, inner_redeem_state: InnerRedeemState, ) -> Result>, DispatchError> { - // TODO: Should just be amount and maybe factor in the remaining amount as well - let collected_redemption = CollectedRedemption::::get(who, investment_id); + let amount_payment_tranche_tokens = + CollectedRedemptionTrancheTokens::::get(who, investment_id); - // Send notification and kill `CollectedRedemption` iff the state includes - // `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` + // Send notification and kill `CollectedRedemptionTrancheTokens` iff the state + // includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` match inner_redeem_state { InnerRedeemState::SwapIntoReturnDone { done_swap, .. } | InnerRedeemState::RedeemingAndSwapIntoReturnDone { done_swap, .. } @@ -555,10 +551,10 @@ impl Pallet { done_swap.currency_in, CollectedAmount { amount_collected: done_swap.amount, - amount_payment: collected_redemption.amount_payment, + amount_payment: amount_payment_tranche_tokens, }, )?; - CollectedRedemption::::remove(who, investment_id); + CollectedRedemptionTrancheTokens::::remove(who, investment_id); Ok(()) } _ => Ok(()), @@ -751,7 +747,7 @@ impl Pallet { Ok(()) } - /// Determines the correct amount for a token swap based on the current + /// Determines the correct amount of a token swap based on the current /// `InvestState` and `RedeemState` corresponding to the `TokenSwapOrderId`. /// /// Returns a tuple of the total swap order amount as well as potentially diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 516b569327..0371f0bff6 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -454,9 +454,13 @@ where } /// Transition all inner states which include - /// `ActiveSwapIntoReturnCurrency` either into `*SwapIntoReturnDone` or + /// `ActiveSwapIntoReturnCurrency`. The transitioned state either includes + /// `*SwapIntoReturnDone` or /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. /// + /// Also supports non-foreign swaps, i.e. those with matching in and out + /// currency. + /// /// Throws if the fulfilled swap direction is not into return currency or if /// the amount exceeds the states active swap amount. /// @@ -481,7 +485,7 @@ where let Swap { amount, .. } = fulfilled_swap; - // edge case: if currency_in matches currency_out, we can immediately fulfill + // Edge case: if currency_in matches currency_out, we can immediately fulfill // the swap match *self { Redeeming { .. } | @@ -554,17 +558,23 @@ where } } - /// Remove `CollectableRedemption` from all states which include it. Either - /// swap it with `ActiveSwapIntoReturnCurrency` if the state did not include - /// an active swap or simply drop it. + /// Apply the transition of the state after collecting a redemption: + /// * If the collected amount (in pool currency) is positive, this indicates + /// that we need to initiate the swap into return currency + /// * If the collected amount is zero, this indicates that the collection is + /// considered to be done. /// - /// Throws if the state includes an active or done swap and either - /// * The in and out currencies do not match the provided ones, or - /// * The collectable amount cannot be incremented by the swap amount - /// (should never happen). + /// Throws if + /// * The current state includes an active/done swap and in and out + /// currencies do not match the provided ones; or + /// * The collected amount is zero but the state does not include a foreign + /// `ActiveSwapIntoReturnCurrency` or `SwapIntoReturnDone` fn transition_collect( &self, collected_swap: Swap, + // TODO: Check whether we need to check this at another place, i.e. when transitioning + // redeem + // amount_unprocessed_redemption: Balance, ) -> Result { ensure!( self.get_active_swap() @@ -574,7 +584,13 @@ where DispatchError::Other("Invalid swap currencies when transitioning collect redemption") ); - match *self { + if collected_swap.currency_in == collected_swap.currency_out { + return Self::transition_collect_non_foreign(&self, collected_swap); + } + + // A collectable redemption is considered to be _done_ iff the amount of pool + // currency returned after calling `collect_redeem` is zero + match self.clone() { Redeeming { .. } | ActiveSwapIntoReturnCurrency { .. } | ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | @@ -582,67 +598,190 @@ where RedeemingAndActiveSwapIntoReturnCurrency { .. } | RedeemingAndSwapIntoReturnDone { .. } | RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), - // TODO: Probably just ignore `collect_amount` - CollectableRedemption => Ok(Self::ActiveSwapIntoReturnCurrency { - swap: collected_swap, - }), - RedeemingAndCollectableRedemption { redeem_amount } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: collected_swap, - }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { - redeem_amount, - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap + CollectableRedemption => { + if collected_swap.amount.is_zero() { + Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + swap: collected_swap, + }) } - }), + }, + RedeemingAndCollectableRedemption { redeem_amount } => { + if collected_swap.amount.is_zero() { + Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: collected_swap, + }) + } + }, + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + if collected_swap.amount.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap + }) + } + else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + redeem_amount, + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + } + }) + } + }, RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: Swap { - amount: collected_swap.amount, - ..collected_swap - }, - done_amount: done_swap.amount - }) + if collected_swap.amount.is_zero() { + Ok(Self::RedeemingAndSwapIntoReturnDone { + redeem_amount, + done_swap, + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: collected_swap.amount, + ..collected_swap + }, + done_amount: done_swap.amount + }) + } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - redeem_amount, - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - done_amount - }) + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => {; + if collected_swap.amount.is_zero() { + Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap, + done_amount + }) + } else { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + redeem_amount, + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + done_amount + }) + } }, CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { - Ok(Self::ActiveSwapIntoReturnCurrency { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - } - }) + if collected_swap.amount.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap, + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + }) + } }, CollectableRedemptionAndSwapIntoReturnDone { done_swap } => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - amount: collected_swap.amount, + if collected_swap.amount.is_zero() { + Ok(Self::SwapIntoReturnDone { + done_swap, + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: collected_swap.amount, + ..collected_swap + }, + done_amount: done_swap.amount, + }) + } + }, + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + if collected_swap.amount.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap, + done_amount + }) + } else { + Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + done_amount + }) + } + }, + } + } + + /// Apply the transition of the state after collecting a redemption in + /// non-foreign currencies. + /// * Ignores any states without `CollectableRedemption`. + /// * Throws for all states with `CollectableRedemption` and + /// `ActiveSwapIntoReturnCurrency` as there can't be an active swap for + /// non-foreign currencies, these should immediately fulfilled. + /// * Else replaces `CollectableRedemption` with `SwapIntoReturnDone` if it + /// did not exist already. If it did, increment the done swap amount by + /// the collected one. + fn transition_collect_non_foreign( + &self, + collected_swap: Swap, + ) -> Result { + match *self { + Redeeming { .. } | + ActiveSwapIntoReturnCurrency { .. } | + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | + SwapIntoReturnDone { .. } | + RedeemingAndActiveSwapIntoReturnCurrency { .. } | + RedeemingAndSwapIntoReturnDone { .. } | + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } | + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | + CollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } | + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => { + Err(DispatchError::Other("Invalid pre state when transitioning collect for same currencies")) + }, + CollectableRedemption => { + if collected_swap.amount.is_zero() { + Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) + } else { + Ok(Self::CollectableRedemptionAndSwapIntoReturnDone { + done_swap: collected_swap, + }) + } + }, + RedeemingAndCollectableRedemption { redeem_amount } => { + if collected_swap.amount.is_zero() { + Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) + } else { + Ok(Self::RedeemingAndSwapIntoReturnDone { + redeem_amount, + done_swap: collected_swap, + }) + } + }, + + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => { + Ok(RedeemingAndSwapIntoReturnDone { + redeem_amount, + done_swap: Swap { + amount: done_swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap - }, - done_amount: done_swap.amount, + } }) }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, + CollectableRedemptionAndSwapIntoReturnDone { done_swap } => { + Ok(SwapIntoReturnDone { + done_swap: Swap { + amount: done_swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap - }, - done_amount + } }) }, + } } } @@ -700,6 +839,13 @@ where } } + /// Handle `decrease` transitions depicted by `msg::decrease` edges in the + /// redeem state diagram: + /// * If the current inner state includes an unprocessed redemption, i.e. is + /// `InnerRedeemState::Redeeming`, decreases the redeeming amount up to + /// its max. Throws if the decrement amount exceeds the previously + /// increased redemption amount. + /// * Else throws for incorrect pre state. fn handle_decrease(&self, amount: Balance) -> Result { let error_not_redeeming = Err(DispatchError::Other( "Invalid redeem state when transitioning a decrease", @@ -766,6 +912,7 @@ where } } + /// Update the inner state if it includes `ActiveSwapIntoReturnCurrency`. fn handle_fulfilled_swap_order( &self, swap: Swap, diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 1c24ef8c5b..9b4112b971 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -248,21 +248,21 @@ pub mod pallet { T::TokenSwapOrderId, >; - /// Maps an investor and their `InvestmentId` to the amount of collected - /// pool currency and the corresponding amount of tranche tokens burned for - /// the conversion based on the fulfillment price(s). + /// Maps an investor and their `InvestmentId` to the amount of + /// tranche tokens burned for the conversion into pool currency based on the + /// fulfillment price(s) during collection. /// /// NOTE: The lifetime of this storage starts with collecting a redemption /// in pool currency and ends with having swapped the entire amount to - /// return currency. + /// return currency which is assumed to be asynchronous. #[pallet::storage] - pub(super) type CollectedRedemption = StorageDoubleMap< + pub(super) type CollectedRedemptionTrancheTokens = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, - CollectedAmount, + T::Balance, ValueQuery, >; From f246ea8c3b539c5539b237c866c24dbd1174ae19 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 16:15:06 +0200 Subject: [PATCH 25/96] refactor: move swap currency check --- libs/types/src/investments.rs | 36 +++++++++- .../foreign-investments/src/impls/invest.rs | 66 +++++-------------- 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 891dbb3264..cadfd2c31a 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -16,7 +16,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; use sp_arithmetic::traits::{EnsureAdd, EnsureSub}; -use sp_runtime::traits::Zero; +use sp_runtime::{traits::Zero, DispatchError, DispatchResult}; use sp_std::cmp::PartialEq; use crate::orders::Order; @@ -185,6 +185,40 @@ pub struct Swap + Swap +{ + /// Ensures that the ingoing and outgoing currencies of two swaps... + /// * Either match fully (in1 = in2, out1 = out2) if the swap direction is + /// the same for both swaps, i.e. (pool, pool) or (return, return) + /// * Or the ingoing and outgoing currencies match (in1 = out2, out1 = in2) + /// if the swap direction is opposite, i.e. (pool, return) or (return, + /// pool) + pub fn ensure_currencies_match( + &self, + other: &Self, + is_same_swap_direction: bool, + ) -> DispatchResult { + if is_same_swap_direction + && self.currency_in != other.currency_in + && self.currency_out != other.currency_out + { + Err(DispatchError::Other( + "Swap currency mismatch for same swap direction", + )) + } else if !is_same_swap_direction + && self.currency_in != other.currency_out + && self.currency_out != other.currency_in + { + Err(DispatchError::Other( + "Swap currency mismatch for opposite swap direction", + )) + } else { + Ok(()) + } + } +} + /// A representation of an executed investment decrement. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 41007438b1..cbf8500e4b 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -14,7 +14,7 @@ use cfg_types::investments::Swap; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, - ArithmeticError, DispatchError, DispatchResult, + ArithmeticError, DispatchError, }; use crate::types::{InvestState, InvestTransition}; @@ -134,7 +134,7 @@ where } // Bump pool swap Self::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { - Self::ensure_currencies_match(true, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, true)?; Ok(Self::ActiveSwapIntoPoolCurrency { swap: Swap { amount: swap.amount.ensure_add(pool_swap.amount)?, @@ -145,7 +145,7 @@ where // Reduce return swap amount by the increasing amount and increase investing amount as // well adding return_done amount by the minimum of active swap amounts Self::ActiveSwapIntoReturnCurrency { swap: return_swap } => { - Self::ensure_currencies_match(false, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, false)?; let invest_amount = swap.amount.min(return_swap.amount); let done_amount = swap.amount.min(return_swap.amount); @@ -190,7 +190,7 @@ where swap: pool_swap, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, true)?; Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { @@ -206,7 +206,7 @@ where swap: return_swap, invest_amount, } => { - Self::ensure_currencies_match(false, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, false)?; let invest_amount = invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; let done_amount = swap.amount.min(return_swap.amount); @@ -253,7 +253,7 @@ where swap: return_swap, done_amount, } => { - Self::ensure_currencies_match(false, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, false)?; let invest_amount = swap.amount.min(return_swap.amount); let done_amount = invest_amount.ensure_add(*done_amount)?; @@ -303,7 +303,7 @@ where done_amount, invest_amount, } => { - Self::ensure_currencies_match(false, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, false)?; let invest_amount = invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; let done_amount = swap @@ -409,7 +409,7 @@ where }, // Increment return done amount up to amount of the active pool swap InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { - Self::ensure_currencies_match(false, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, false)?; if swap.amount == pool_swap.amount { Ok(Self::SwapIntoReturnDone { done_swap: swap }) @@ -433,7 +433,7 @@ where swap: pool_swap, invest_amount, } => { - Self::ensure_currencies_match(false, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, false)?; let done_amount = swap.amount.min(pool_swap.amount); let invest_amount = invest_amount.ensure_sub(done_amount)?; let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; @@ -487,7 +487,7 @@ where swap: return_swap, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { @@ -511,7 +511,7 @@ where done_amount, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; let amount = return_swap.amount.ensure_add(swap.amount)?; if swap.amount < *invest_amount { @@ -573,7 +573,7 @@ where )), // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { - Self::ensure_currencies_match(true, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, true)?; if swap.amount == pool_swap.amount { Ok(Self::InvestmentOngoing { @@ -596,7 +596,7 @@ where }, // Increment done_return by swapped amount InvestState::ActiveSwapIntoReturnCurrency { swap: return_swap } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDone { done_swap: swap }) @@ -620,7 +620,7 @@ where swap: pool_swap, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, pool_swap)?; + swap.ensure_currencies_match(pool_swap, true)?; let invest_amount = invest_amount.ensure_add(swap.amount)?; if swap.amount == pool_swap.amount { @@ -645,7 +645,7 @@ where swap: return_swap, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; if swap.amount == return_swap.amount { Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { @@ -675,7 +675,7 @@ where swap: return_swap, done_amount, } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { @@ -706,7 +706,7 @@ where done_amount, invest_amount, } => { - Self::ensure_currencies_match(true, &swap, return_swap)?; + swap.ensure_currencies_match(return_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; if swap.amount == return_swap.amount { @@ -822,36 +822,4 @@ where )) } } - - // TODO(@review): Can we ensure this check at an earlier stage? - - /// Ensures that the ingoing and outgoing currencies of two swaps... - /// * Either match fully (in1 = in2, out1 = out2) if the swap direction is - /// the same for both swaps, i.e. (pool, pool) or (return, return) - /// * Or the ingoing and outgoing currencies match (in1 = out2, out1 = in2) - /// if the swap direction is opposite, i.e. (pool, return) or (return, - /// pool) - fn ensure_currencies_match( - is_same_swap_direction: bool, - swap_1: &Swap, - swap_2: &Swap, - ) -> DispatchResult { - if is_same_swap_direction - && swap_1.currency_in != swap_2.currency_in - && swap_1.currency_out != swap_2.currency_out - { - Err(DispatchError::Other( - "Swap currency mismatch for same swap direction", - )) - } else if !is_same_swap_direction - && swap_1.currency_in != swap_2.currency_out - && swap_1.currency_out != swap_2.currency_in - { - Err(DispatchError::Other( - "Swap currency mismatch for opposite swap direction", - )) - } else { - Ok(()) - } - } } From cff15fe02fe0a141a456698afb49d370ceb7b563 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 17:43:56 +0200 Subject: [PATCH 26/96] feat: epoch executions --- .../foreign-investments/src/impls/invest.rs | 98 +++++++++++ pallets/foreign-investments/src/impls/mod.rs | 6 +- .../foreign-investments/src/impls/redeem.rs | 155 +++++++++++------- pallets/foreign-investments/src/lib.rs | 73 ++++++++- pallets/foreign-investments/src/types.rs | 15 +- 5 files changed, 282 insertions(+), 65 deletions(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index cbf8500e4b..c1596e0ce6 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -39,6 +39,9 @@ where InvestTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(&self, swap) } + InvestTransition::EpochExecution(amount_unprocessed) => { + Self::handle_epoch_execution(&self, amount_unprocessed) + } } } @@ -822,4 +825,99 @@ where )) } } + + /// Update or kill the unprocessed investment amount. + /// * If the state does not include `InvestmentOngoing` and the unprocessed + /// amount is not zero, there is nothing to transition, return the current + /// state. If the unprocessed amount is zero, state is corrupted. + /// * Else If the provided `unprocessed_amount` is zero, remove + /// `InvestmentOngoing` from the state + /// * Else set the `invest_amount` to `unprocessed_amount` + fn handle_epoch_execution(&self, unprocessed_amount: Balance) -> Result { + match *self { + Self::InvestmentOngoing { .. } => { + if unprocessed_amount.is_zero() { + Ok(Self::NoState) + } else { + Ok(Self::InvestmentOngoing { + invest_amount: unprocessed_amount, + }) + } + } + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => { + if unprocessed_amount.is_zero() { + Ok(Self::ActiveSwapIntoPoolCurrency { swap }) + } else { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap, + invest_amount: unprocessed_amount, + }) + } + } + Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, .. } => { + if unprocessed_amount.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrency { swap }) + } else { + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap, + invest_amount: unprocessed_amount, + }) + } + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + .. + } => { + if unprocessed_amount.is_zero() { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount }) + } else { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount: unprocessed_amount, + }, + ) + } + } + Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, .. } => { + if unprocessed_amount.is_zero() { + Ok(Self::SwapIntoReturnDone { done_swap }) + } else { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap, + invest_amount: unprocessed_amount, + }) + } + } + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + .. + } => { + if unprocessed_amount.is_zero() { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap, + done_amount, + }) + } else { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount: unprocessed_amount, + }) + } + } + state => { + if unprocessed_amount.is_zero() { + Ok(state) + } else { + Err(DispatchError::Other( + "Invalid invest state when transitioning epoch execution", + )) + } + } + } + } } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 7224726125..bf89278cfa 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -273,7 +273,7 @@ impl Pallet { /// * When updating token swap orders, only `handle_swap_order` should /// be called. #[transactional] - fn apply_invest_state_transition( + pub(crate) fn apply_invest_state_transition( who: &T::AccountId, investment_id: T::InvestmentId, state: InvestState, @@ -387,12 +387,12 @@ impl Pallet { /// assume the impl of `::Investment` handles this case. /// /// NOTES: - /// * Must be called after transitioning any `RedeemState` via + /// * Must be called after transitionin g any `RedeemState` via /// `transition` to update the chain storage. /// * When updating token swap orders, only `handle_swap_order` should /// be called. #[transactional] - fn apply_redeem_state_transition( + pub(crate) fn apply_redeem_state_transition( who: &T::AccountId, investment_id: T::InvestmentId, state: RedeemState, diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 0371f0bff6..b4099e9d3d 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -57,6 +57,9 @@ where Self::handle_fulfilled_swap_order(&self, swap) } RedeemTransition::Collect(swap) => Self::handle_collect(&self, swap), + RedeemTransition::EpochExecution(amount_unprocessed) => { + Self::handle_epoch_execution(&self, amount_unprocessed) + } } } @@ -141,13 +144,37 @@ where } } - // pub(crate) increase_invested(&self, amount: Balance) -> Result { match self { - // Self::InvestedAnd { invest_amount, inner } => { - - // } - // } - // } + /// Update or kill the unprocessed redemption amount of the inner state. + /// * If the outer state does not include an inner state with `Redeeming`, + /// there is nothing to transition, i.e. we return the current state + /// * Else If the provided `unprocessed_amount` is zero, remove `Redeeming` + /// from the inner state + /// * Else set the `redeem_amount` to `unprocessed_amount` + fn handle_epoch_execution(&self, amount_unprocessed: Balance) -> Result { + match *self { + RedeemState::NoState | RedeemState::Invested { .. } => Ok(*self), + RedeemState::NotInvestedAnd { inner } => match inner { + Redeeming { .. } if !amount_unprocessed.is_zero() => Ok(Self::Invested { + invest_amount: amount_unprocessed, + }), + state => Ok(RedeemState::NotInvestedAnd { + inner: state.set_existing_redeem_amount(amount_unprocessed)?, + }), + }, + RedeemState::InvestedAnd { + inner, + invest_amount, + } => match inner { + Redeeming { .. } if !amount_unprocessed.is_zero() => Ok(Self::Invested { + invest_amount: amount_unprocessed, + }), + state => Ok(RedeemState::InvestedAnd { + inner: state.set_existing_redeem_amount(amount_unprocessed)?, + invest_amount, + }), + }, + } + } } impl InnerRedeemState @@ -399,7 +426,25 @@ where } } - /// Sets the redeeming amount to the provided value: + /// Removes `Redeeming` from the state. + fn remove_redeem_amount(&self) -> Result { + match *self { + Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), + RedeemingAndCollectableRedemption { .. } => Ok(CollectableRedemption), + RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(ActiveSwapIntoReturnCurrency { swap }), + RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(SwapIntoReturnDone { done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), + // Throw for states without `Redeeming` + // TODO: Create pallet error NotRedeeming + inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), + } + } + + /// Either adds a non existing redeeming amount to the state or overwrites + /// it. /// * If the value is not zero and the state involves `Redeeming`: Sets the /// amount. /// * Else if the value is not zero and the state does not involve @@ -408,48 +453,46 @@ where /// * If the value is zero and the state includes `Redeeming`: Removes /// `Redeeming` from the state. /// * Else throws. + fn add_or_overwrite_redeem_amount(&self, amount: Balance) -> Result { + if amount.is_zero() { + return Self::remove_redeem_amount(&self); + } + match *self { + Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), + RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), + RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), + ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), + ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), + SwapIntoReturnDone { done_swap } => Ok(RedeemingAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), + CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), + } + } + + /// Sets the redeeming amount of the state to the given amount. /// - /// NOTE: If setting the amount to a non-zero value, assumes this function - /// is **only called on inner states of `RedeemState::InvestedAnd`** as the - /// redeeming amounts can at most equal the processed investment amount. - /// Since the inner state has no knowledge about the investment amount, this - /// check must be done beforehand. - fn set_redeem_amount(&self, amount: Balance) -> Result { - // Remove `Redeeming` from state + /// Throws if the the state does not include `Redeeming`. + fn set_existing_redeem_amount(&self, amount: Balance) -> Result { if amount.is_zero() { - match *self { - Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), - RedeemingAndCollectableRedemption { .. } => Ok(CollectableRedemption), - RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(ActiveSwapIntoReturnCurrency { swap }), - RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(SwapIntoReturnDone { done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), - // Throw for states without `Redeeming` - // TODO: Create pallet error NotRedeeming - inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), - } + return Self::remove_redeem_amount(&self); } - // Set `redeeming` to non-zero value. Add `Redeeming` if not part of state yet. - else { - match *self { - Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), - SwapIntoReturnDone { done_swap } => Ok(RedeemingAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), - CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), - } + match *self { + Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), + RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), + RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + _ => Err(DispatchError::Other("Cannot set existing redeem amount of inner redeem state which does not include `Redeeming`")), } } @@ -651,7 +694,7 @@ where }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => {; + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { if collected_swap.amount.is_zero() { Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, @@ -827,12 +870,12 @@ where } => { if &amount == invest_amount { Ok(Self::NotInvestedAnd { - inner: inner.set_redeem_amount(amount)?, + inner: inner.add_or_overwrite_redeem_amount(amount)?, }) } else { Ok(Self::InvestedAnd { invest_amount: invest_amount.ensure_sub(amount)?, - inner: inner.set_redeem_amount(amount)?, + inner: inner.add_or_overwrite_redeem_amount(amount)?, }) } } @@ -867,7 +910,7 @@ where }), _ => Ok(Self::InvestedAnd { invest_amount: amount, - inner: inner.set_redeem_amount(Balance::zero())?, + inner: inner.add_or_overwrite_redeem_amount(Balance::zero())?, }), }, Self::InvestedAnd { @@ -879,7 +922,7 @@ where Redeeming { .. } => Ok(Self::Invested { invest_amount }), _ => Ok(Self::InvestedAnd { invest_amount, - inner: inner.set_redeem_amount(Balance::zero())?, + inner: inner.add_or_overwrite_redeem_amount(Balance::zero())?, }), } } @@ -890,12 +933,10 @@ where let redeem_amount = old_redeem_amount.ensure_sub(amount)?; match self { - Self::NoState | Self::Invested { .. } | Self::Invested { .. } => { - error_not_redeeming - } + Self::NoState | Self::Invested { .. } => error_not_redeeming, Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { invest_amount: amount, - inner: inner.set_redeem_amount(redeem_amount)?, + inner: inner.add_or_overwrite_redeem_amount(redeem_amount)?, }), Self::InvestedAnd { invest_amount, @@ -904,7 +945,7 @@ where let invest_amount = invest_amount.ensure_add(amount)?; Ok(Self::InvestedAnd { invest_amount, - inner: inner.set_redeem_amount(redeem_amount)?, + inner: inner.add_or_overwrite_redeem_amount(redeem_amount)?, }) } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 9b4112b971..a79dfe1cd8 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -41,13 +41,16 @@ pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentI #[frame_support::pallet] pub mod pallet { use cfg_traits::{ - investments::{InvestmentCollector, TrancheCurrency}, + investments::{Investment as InvestmentT, InvestmentCollector, TrancheCurrency}, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, }; - use frame_support::{dispatch::HasCompact, pallet_prelude::*}; + use frame_support::{ + dispatch::HasCompact, + pallet_prelude::{DispatchResultWithPostInfo, *}, + }; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; use types::{InvestState, RedeemState, TokenSwapReason}; @@ -114,7 +117,7 @@ pub mod pallet { /// The internal investment type which handles the actual investment on /// top of the wrapper implementation of this Pallet - type Investment: cfg_traits::investments::Investment< + type Investment: InvestmentT< Self::AccountId, Amount = Self::Balance, CurrencyId = Self::CurrencyId, @@ -334,5 +337,67 @@ pub mod pallet { } #[pallet::call] - impl Pallet {} + impl Pallet { + /// Attempts to transition an `InvestState` after an epoch execution: + /// * If the state includes `InvestmentOngoing` and the unprocessed + /// investment amount is zero, removes `InvestmentOngoing`. + /// * If the state includes `InvestmentOngoing` and the unprocessed + /// investment amount is positive, updates the `invest_amount` to the + /// unprocessed one. + /// + /// NOOP: If the unprocessed investment amount is zero or the state does + /// not include `InvestmentOngoing` + // TODO: weights/benchmark, numbers chosen by rough estimation + #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] + #[pallet::call_index(1)] + pub fn nudge_invest_state( + origin: OriginFor, + investor: T::AccountId, + investment_id: T::InvestmentId, + ) -> DispatchResultWithPostInfo { + if let Some(invest_state) = InvestmentState::::get(&investor, investment_id) { + let amount_unprocessed_investment = + T::Investment::investment(&investor, investment_id)?; + let new_state = invest_state.transition( + types::InvestTransition::EpochExecution(amount_unprocessed_investment), + )?; + Pallet::::apply_invest_state_transition(&investor, investment_id, new_state)?; + + Ok(Some(T::DbWeight::get().reads_writes(5, 5)).into()) + } else { + Ok(Some(T::DbWeight::get().reads(1)).into()) + } + } + + /// Attempts to transition a `RedeemState` after an epoch execution: + /// * If the inner state includes `Redeeming` and the unprocessed + /// redemption amount is zero, removes `Redeeming`. + /// * If the inner state includes `Redeeming` and the unprocessed + /// redemption amount is positive, updates the amount to the + /// unprocessed one. + /// + /// NOOP: If the unprocessed redemption amount is zero or the inner + /// state does not include `Redeeming`. + // TODO: weights/benchmark, numbers chosen by rough estimation + #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] + #[pallet::call_index(2)] + pub fn nudge_redeem_state( + origin: OriginFor, + investor: T::AccountId, + investment_id: T::InvestmentId, + ) -> DispatchResultWithPostInfo { + if let Some(redeem_state) = RedemptionState::::get(&investor, investment_id) { + let amount_unprocessed_redemption = + T::Investment::redemption(&investor, investment_id)?; + let new_state = redeem_state.transition( + types::RedeemTransition::EpochExecution(amount_unprocessed_redemption), + )?; + Pallet::::apply_redeem_state_transition(&investor, investment_id, new_state)?; + + Ok(Some(T::DbWeight::get().reads_writes(5, 5)).into()) + } else { + Ok(Some(T::DbWeight::get().reads(1)).into()) + } + } + } } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 4316574a33..b7ca1ee843 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -31,7 +31,18 @@ pub enum TokenSwapReason { /// into a pool currency or back, if the investment is decreased before it is /// fully processed. #[derive( - Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, + Clone, + Default, + PartialOrd, + Ord, + Copy, + PartialEq, + Eq, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, )] pub enum InvestState< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, @@ -145,6 +156,7 @@ pub enum InvestTransition< /// * If the previous state includes `ActiveSwapIntoReturnCurrency`, /// `currency_in` is the return currency. FulfillSwapOrder(Swap), + EpochExecution(Balance), } /// Reflects all states a foreign redemption can have until transferred to the @@ -313,4 +325,5 @@ pub enum RedeemTransition< DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), Collect(Swap), + EpochExecution(Balance), } From bd85c67e62dc74452dc878a6a7ff1a0d96bcc396 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 17 Aug 2023 17:54:58 +0200 Subject: [PATCH 27/96] =?UTF-8?q?wip:=20=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/types/src/tokens.rs | 8 ++-- pallets/foreign-investments/src/impls/mod.rs | 1 + .../foreign-investments/src/impls/redeem.rs | 38 +++++++++---------- pallets/foreign-investments/src/lib.rs | 4 ++ 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/libs/types/src/tokens.rs b/libs/types/src/tokens.rs index a59108a19b..3d96b0abd1 100644 --- a/libs/types/src/tokens.rs +++ b/libs/types/src/tokens.rs @@ -308,10 +308,10 @@ pub enum LiquidityPoolsWrappedToken { }, } -impl Into for LiquidityPoolsWrappedToken { - fn into(self) -> DomainAddress { - match self { - Self::EVM { chain_id, address } => DomainAddress::EVM(chain_id, address), +impl From for DomainAddress { + fn from(token: LiquidityPoolsWrappedToken) -> Self { + match token { + LiquidityPoolsWrappedToken::EVM { chain_id, address } => Self::EVM(chain_id, address), } } } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index bf89278cfa..110b63d49c 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -138,6 +138,7 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { + // TODO: Check if we can drop the below line let pre_amount = T::Investment::redemption(who, investment_id.clone())?; let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); let post_state = pre_state.transition(RedeemTransition::DecreaseRedeemOrder(amount))?; diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index b4099e9d3d..48f72facce 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -71,7 +71,7 @@ where pub(crate) fn get_active_swap(&self) -> Option> { match self { Self::NoState => None, - Self::Invested { invest_amount } => None, + Self::Invested { .. } => None, Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { inner.get_active_swap() } @@ -85,7 +85,7 @@ where pub(crate) fn get_redeeming_amount(&self) -> Option { match self { Self::NoState => None, - Self::Invested { invest_amount } => None, + Self::Invested { .. } => None, Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { inner.get_redeeming_amount() } @@ -439,7 +439,7 @@ where RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), // Throw for states without `Redeeming` // TODO: Create pallet error NotRedeeming - inner => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), + _ => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), } } @@ -458,14 +458,14 @@ where return Self::remove_redeem_amount(&self); } match *self { - Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), + RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), + RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), @@ -484,14 +484,14 @@ where return Self::remove_redeem_amount(&self); } match *self { - Redeeming { redeem_amount } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { redeem_amount } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), + RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), + RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), _ => Err(DispatchError::Other("Cannot set existing redeem amount of inner redeem state which does not include `Redeeming`")), } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index a79dfe1cd8..4a3c46038d 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -355,6 +355,8 @@ pub mod pallet { investor: T::AccountId, investment_id: T::InvestmentId, ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + if let Some(invest_state) = InvestmentState::::get(&investor, investment_id) { let amount_unprocessed_investment = T::Investment::investment(&investor, investment_id)?; @@ -386,6 +388,8 @@ pub mod pallet { investor: T::AccountId, investment_id: T::InvestmentId, ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + if let Some(redeem_state) = RedemptionState::::get(&investor, investment_id) { let amount_unprocessed_redemption = T::Investment::redemption(&investor, investment_id)?; From b5fb73c9cbe2f355d5c8c40392120e8a2a10435b Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 10:20:04 +0200 Subject: [PATCH 28/96] feat: add cancel invest/redeem order msgs --- pallets/foreign-investments/src/impls/mod.rs | 2 - pallets/liquidity-pools/src/inbound.rs | 50 ++++++++- pallets/liquidity-pools/src/lib.rs | 28 ++++- pallets/liquidity-pools/src/message.rs | 104 +++++++++++++++++++ 4 files changed, 178 insertions(+), 6 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 110b63d49c..df998e6d2d 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -198,7 +198,6 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, ) -> Result { - // TODO: Needs to be translated from `pool_currency` to `return_currency` T::Investment::investment(who, investment_id) } @@ -206,7 +205,6 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, ) -> Result { - // TODO: Needs to be translated from `pool_currency` to `return_currency` T::Investment::redemption(who, investment_id) } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 4680babfb1..c590b46363 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -149,6 +149,26 @@ impl Pallet { Ok(()) } + /// Cancels an invest order by decreasing by the entire unprocessed + /// investment amount. + /// + /// On success, a swap back into the provided return currency initiated. + /// + /// The finalization of this call (fulfillment of the swap) is assumed to be + /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` + /// which burns the corresponding amount in return currency and dispatches + /// `ExecutedDecreaseInvestOrder`. + pub fn handle_cancel_invest_order( + pool_id: T::PoolId, + tranche_id: T::TrancheId, + investor: T::AccountId, + currency_index: GeneralCurrencyIndexOf, + ) -> DispatchResult { + let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let amount = T::ForeignInvestment::investment(&investor, invest_id)?; + Self::handle_decrease_invest_order(pool_id, tranche_id, investor, currency_index, amount) + } + /// Increases an existing redemption order of the investor. /// /// Transfers the increase redemption amount from the holdings of the @@ -157,7 +177,7 @@ impl Pallet { /// /// Assumes that the amount of tranche tokens has been locked in the /// `DomainLocator` account of the origination domain beforehand. - pub fn handle_increase_redemption( + pub fn handle_increase_redeem_order( pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, @@ -190,7 +210,7 @@ impl Pallet { /// NOTE: In contrast to investments, redemption decrements happen /// fully synchronously as they can only be called in between increasing a /// redemption and its (full) processing. - pub fn handle_decrease_redemption( + pub fn handle_decrease_redeem_order( pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, @@ -229,6 +249,32 @@ impl Pallet { Ok(()) } + /// Cancels an existing redemption order of the investor by decreasing the + /// redemption by the entire unprocessed amount. + /// + /// Initiates a return `ExecutedDecreaseRedemption` message to refund the + /// decreased amount on the source domain. + pub fn handle_cancel_redeem_order( + pool_id: T::PoolId, + tranche_id: T::TrancheId, + investor: T::AccountId, + investor_bytes: [u8; 32], + currency_index: GeneralCurrencyIndexOf, + destination: Domain, + ) -> DispatchResult { + let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let amount = T::ForeignInvestment::redemption(&investor, invest_id)?; + Self::handle_decrease_redeem_order( + pool_id, + tranche_id, + investor, + investor_bytes, + currency_index, + amount, + destination, + ) + } + /// Collect the results of a user's invest orders for the given investment /// id. If any amounts are not fulfilled, they are directly appended to the /// next active order for this investment. diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 83734d5ad3..c7b675ddc5 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -859,7 +859,7 @@ pub mod pallet { investor, amount, .. - } => Self::handle_increase_redemption( + } => Self::handle_increase_redeem_order( pool_id, tranche_id, investor.into(), @@ -872,7 +872,7 @@ pub mod pallet { investor, currency, amount, - } => Self::handle_decrease_redemption( + } => Self::handle_decrease_redeem_order( pool_id, tranche_id, investor.into(), @@ -905,6 +905,30 @@ pub mod pallet { investor.into(), currency.into(), ), + Message::CancelInvestOrder { + pool_id, + tranche_id, + investor, + currency, + } => Self::handle_cancel_invest_order( + pool_id, + tranche_id, + investor.into(), + currency.into(), + ), + Message::CancelRedeemOrder { + pool_id, + tranche_id, + investor, + currency, + } => Self::handle_cancel_redeem_order( + pool_id, + tranche_id, + investor.into(), + investor, + currency.into(), + sender.into(), + ), _ => Err(Error::::InvalidIncomingMessage.into()), }?; diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 5dd0d22df0..a83971c6fd 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -278,6 +278,42 @@ where /// How many tranche tokens were actually redeemed tranche_tokens_payout: Balance, }, + /// Cancel an unprocessed invest order for the specified pair of pool and + /// tranche token. + /// + /// Special instance of `DecreaseInvestOrder` where the amount is chosen + /// properly to cancel out the ongoing investment. Required for ERC4646. + /// + /// On success, triggers a message sent back to the sending domain. + /// The message will take care of re-funding the investor with the given + /// amount the order was reduced with. The `investor` address is used as + /// the receiver of that tokens. + /// + /// Directionality: Centrifuge <- EVM Domain. + CancelInvestOrder { + pool_id: PoolId, + tranche_id: TrancheId, + investor: Address, + currency: u128, + }, + /// Reduce the redeem order amount for the specified pair of pool and + /// tranche token. + /// + /// Special instance of `DecreaseRedeemOrder` where the amount is chosen + /// properly to cancel out the ongoing redemption. Required for ERC4646. + /// + /// On success, triggers a message sent back to the sending domain. + /// The message will take care of re-funding the investor with the given + /// amount the order was reduced with. The `investor` address is used as + /// the receiver of that tokens. + /// + /// Directionality: Centrifuge <- EVM Domain. + CancelRedeemOrder { + pool_id: PoolId, + tranche_id: TrancheId, + investor: Address, + currency: u128, + }, } impl< @@ -315,6 +351,8 @@ impl< Self::ExecutedDecreaseRedeemOrder { .. } => 16, Self::ExecutedCollectInvest { .. } => 17, Self::ExecutedCollectRedeem { .. } => 18, + Self::CancelInvestOrder { .. } => 19, + Self::CancelRedeemOrder { .. } => 20, } } } @@ -576,6 +614,34 @@ impl< encode_be(tranche_tokens_payout), ], ), + Message::CancelInvestOrder { + pool_id, + tranche_id, + investor, + currency, + } => encoded_message( + self.call_type(), + vec![ + encode_be(pool_id), + tranche_id.encode(), + investor.to_vec(), + encode_be(currency), + ], + ), + Message::CancelRedeemOrder { + pool_id, + tranche_id, + investor, + currency, + } => encoded_message( + self.call_type(), + vec![ + encode_be(pool_id), + tranche_id.encode(), + investor.to_vec(), + encode_be(currency), + ], + ), } } @@ -698,6 +764,18 @@ impl< currency_payout: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, }), + 19 => Ok(Self::CancelInvestOrder { + pool_id: decode_be_bytes::<8, _, _>(input)?, + tranche_id: decode::<16, _, _>(input)?, + investor: decode::<32, _, _>(input)?, + currency: decode_be_bytes::<16, _, _>(input)?, + }), + 20 => Ok(Self::CancelRedeemOrder { + pool_id: decode_be_bytes::<8, _, _>(input)?, + tranche_id: decode::<16, _, _>(input)?, + investor: decode::<32, _, _>(input)?, + currency: decode_be_bytes::<16, _, _>(input)?, + }), _ => Err(codec::Error::from( "Unsupported decoding for this Message variant", )), @@ -957,6 +1035,19 @@ mod tests { ) } + #[test] + fn cancel_invest_order() { + test_encode_decode_identity( + LiquidityPoolsMessage::CancelInvestOrder { + pool_id: 1, + tranche_id: default_tranche_id(), + investor: default_address_32(), + currency: TOKEN_ID, + }, + "130000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b", + ) + } + #[test] fn increase_redeem_order() { test_encode_decode_identity( @@ -985,6 +1076,19 @@ mod tests { ) } + #[test] + fn cancel_redeem_order() { + test_encode_decode_identity( + LiquidityPoolsMessage::CancelRedeemOrder { + pool_id: 1, + tranche_id: default_tranche_id(), + investor: default_address_32(), + currency: TOKEN_ID, + }, + "140000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b", + ) + } + #[test] fn collect_invest() { test_encode_decode_identity( From 8a2640ade4a6e2ec0b96851d3134ea1503fe1b1d Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 11:36:12 +0200 Subject: [PATCH 29/96] feat: add collect_for extrinsics --- pallets/liquidity-pools/src/hooks.rs | 4 +- pallets/liquidity-pools/src/inbound.rs | 27 ++++++------ pallets/liquidity-pools/src/lib.rs | 60 ++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 4d32eca141..b8b19a5fd2 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -62,7 +62,7 @@ where currency_payout: status.amount_decreased, }; - T::OutboundQueue::submit(investor, domain_address.into(), message)?; + T::OutboundQueue::submit(investor, domain_address.domain(), message)?; Ok(()) } @@ -100,7 +100,7 @@ where tranche_tokens_payout: status.amount_tranche_tokens_payout, }; - T::OutboundQueue::submit(investor, domain_address.into(), message)?; + T::OutboundQueue::submit(investor, domain_address.domain(), message)?; Ok(()) } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index c590b46363..5e5b5d397a 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -30,7 +30,10 @@ use sp_runtime::{ use crate::{pallet::Error, Config, GeneralCurrencyIndexOf, Message, MessageOf, Pallet}; -impl Pallet { +impl Pallet +where + T::AccountId: Into<[u8; 32]>, +{ /// Executes a transfer from another domain exclusively for /// non-tranche-tokens. /// @@ -214,10 +217,9 @@ impl Pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - investor_bytes: [u8; 32], currency_index: GeneralCurrencyIndexOf, amount: ::Balance, - destination: Domain, + destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; // TODO(@review): This is exactly `amount` as we can only decrement up to the @@ -231,7 +233,7 @@ impl Pallet { T::Tokens::transfer( invest_id.into(), &investor, - &Domain::convert(destination.clone()), + &Domain::convert(destination.domain()), tranche_tokens_payout, false, )?; @@ -239,12 +241,12 @@ impl Pallet { let message: MessageOf = Message::ExecutedDecreaseRedeemOrder { pool_id, tranche_id, - investor: investor_bytes, + investor: investor.clone().into(), currency: currency_index.index, tranche_tokens_payout: tranche_tokens_payout, }; - T::OutboundQueue::submit(investor, destination, message)?; + T::OutboundQueue::submit(investor, destination.domain(), message)?; Ok(()) } @@ -258,9 +260,8 @@ impl Pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - investor_bytes: [u8; 32], currency_index: GeneralCurrencyIndexOf, - destination: Domain, + destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let amount = T::ForeignInvestment::redemption(&investor, invest_id)?; @@ -268,7 +269,6 @@ impl Pallet { pool_id, tranche_id, investor, - investor_bytes, currency_index, amount, destination, @@ -290,9 +290,8 @@ impl Pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - investor_bytes: [u8; 32], currency_index: GeneralCurrencyIndexOf, - destination: Domain, + destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; @@ -304,7 +303,7 @@ impl Pallet { T::Tokens::transfer( invest_id.into(), &investor, - &Domain::convert(destination.clone()), + &Domain::convert(destination.domain()), amount_tranche_tokens_payout, false, )?; @@ -312,13 +311,13 @@ impl Pallet { let message: MessageOf = Message::ExecutedCollectInvest { pool_id, tranche_id, - investor: investor_bytes, + investor: investor.clone().into(), currency: currency_index.index, currency_payout: amount_currency_payout, tranche_tokens_payout: amount_tranche_tokens_payout, }; - T::OutboundQueue::submit(investor, destination, message)?; + T::OutboundQueue::submit(investor, destination.domain(), message)?; Ok(()) } diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index c7b675ddc5..25469de018 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -320,7 +320,7 @@ pub mod pallet { #[pallet::call] impl Pallet where - ::AccountId: From<[u8; 32]>, + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { /// Set a Domain's router #[pallet::weight(< T as Config >::WeightInfo::set_domain_router())] @@ -643,7 +643,7 @@ pub mod pallet { /// Allow a currency to be used as a pool currency and to invest in a /// pool on the domain derived from the given currency. - #[pallet::call_index(90)] + #[pallet::call_index(9)] #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] pub fn allow_pool_currency( origin: OriginFor, @@ -685,6 +685,51 @@ pub mod pallet { Ok(()) } + + /// Collect a user's foreign investment as if we had received a + /// `CollectInvest` message from another domain. + #[pallet::call_index(10)] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] + pub fn collect_foreign_investment_for( + origin: OriginFor, + pool_id: T::PoolId, + tranche_id: T::TrancheId, + investor: T::AccountId, + currency: CurrencyIdOf, + destination: DomainAddress, + ) -> DispatchResult { + ensure_signed(origin)?; + let currency_index = currency.try_into()?; + + Self::handle_collect_investment( + pool_id, + tranche_id, + investor, + currency_index, + destination, + )?; + + Ok(()) + } + + /// Collect a user's foreign redemption as if we had received a + /// `CollectRedeem` message from another domain. + #[pallet::call_index(11)] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] + pub fn collect_foreign_redemption_for( + origin: OriginFor, + pool_id: T::PoolId, + tranche_id: T::TrancheId, + investor: T::AccountId, + currency: CurrencyIdOf, + ) -> DispatchResult { + ensure_signed(origin)?; + let currency_index = currency.try_into()?; + + Self::handle_collect_redemption(pool_id, tranche_id, investor, currency_index)?; + + Ok(()) + } } impl Pallet { @@ -800,7 +845,7 @@ pub mod pallet { impl InboundQueue for Pallet where - ::AccountId: From<[u8; 32]>, + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { type Message = MessageOf; type Sender = DomainAddress; @@ -876,10 +921,9 @@ pub mod pallet { pool_id, tranche_id, investor.into(), - investor, currency.into(), amount, - sender.into(), + sender, ), Message::CollectInvest { pool_id, @@ -890,9 +934,8 @@ pub mod pallet { pool_id, tranche_id, investor.into(), - investor, currency.into(), - sender.into(), + sender, ), Message::CollectRedeem { pool_id, @@ -925,9 +968,8 @@ pub mod pallet { pool_id, tranche_id, investor.into(), - investor, currency.into(), - sender.into(), + sender, ), _ => Err(Error::::InvalidIncomingMessage.into()), }?; From c1787299b2da8122ad69a24b1208c9e5b8d2a69b Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 16:52:45 +0200 Subject: [PATCH 30/96] feat: add simple poc stable conversion --- libs/traits/src/investments.rs | 2 + libs/traits/src/lib.rs | 23 ++++++ .../foreign-investments/src/impls/invest.rs | 8 -- pallets/foreign-investments/src/impls/mod.rs | 19 +++-- pallets/foreign-investments/src/lib.rs | 20 ++++- pallets/liquidity-pools/src/inbound.rs | 13 +++- runtime/altair/src/lib.rs | 5 +- runtime/common/src/lib.rs | 75 +++++++++++++++++++ runtime/development/src/lib.rs | 5 +- 9 files changed, 148 insertions(+), 22 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 7cc5eae6ac..4da4de539b 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -345,6 +345,8 @@ pub trait ForeignInvestment { fn collect_foreign_investment( who: &AccountId, investment_id: Self::InvestmentId, + return_currency: Self::CurrencyId, + pool_currency: Self::CurrencyId, ) -> Result; /// Collect the results of a user's foreign redeem orders for the given diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 43381793f0..396a2d53df 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -513,3 +513,26 @@ pub trait StatusNotificationHook { /// Notify that the status has changed for the given id fn notify_status_change(id: Self::Id, status: Self::Status) -> Result<(), Self::Error>; } + +/// Trait to synchronously provide a currency conversion estimation for foreign +/// currencies into/from pool currencies. +pub trait SimpleCurrencyConversion { + type Currency; + type Balance; + type Error; + + /// Estimate the worth of a foreign stable currency in a particular pool + /// currency. + fn foreign_to_pool( + currency_foreign: Self::Currency, + amount_foreign: Self::Balance, + currency_pool: Self::Currency, + ) -> Result; + + /// Estimate the worth of a pool currency in a particular foreign currency. + fn pool_to_foreign( + currency_pool: Self::Currency, + amount_pool: Self::Balance, + currency_foreign: Self::Currency, + ) -> Result; +} diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index c1596e0ce6..320a9984d2 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -121,7 +121,6 @@ where /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! fn handle_increase(&self, swap: Swap) -> Result { - // TODO(@review): Can we check this at an earlier stage? if swap.currency_in == swap.currency_out { return Self::handle_increase_non_foreign(&self, swap); } @@ -383,7 +382,6 @@ where /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! fn handle_decrease(&self, swap: Swap) -> Result { - // TODO(@review): Can we check this at an earlier stage? if swap.currency_in == swap.currency_out { return Self::handle_decrease_non_foreign(&self, swap); } @@ -744,9 +742,6 @@ where } } - // TODO(@review): Do we need to handle this case at all or assume to always have - // required swaps through foreign investments? - /// Handle increase transitions for the same incoming and outgoing /// currencies. /// @@ -788,9 +783,6 @@ where } } - // TODO(@review): Do we need to handle this case at all or assume to always have - // required swaps through foreign investments? - /// Handle decrease transitions for the same incoming and outgoing /// currencies. /// diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index df998e6d2d..732bf2ed9b 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -13,7 +13,7 @@ use cfg_traits::{ investments::{ForeignInvestment, Investment, InvestmentCollector}, - StatusNotificationHook, TokenSwaps, + SimpleCurrencyConversion, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, @@ -138,11 +138,14 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { - // TODO: Check if we can drop the below line - let pre_amount = T::Investment::redemption(who, investment_id.clone())?; + let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id.clone())?; let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = pre_state.transition(RedeemTransition::DecreaseRedeemOrder(amount))?; + frame_support::ensure!( + unprocessed_redeem_amount == pre_state.get_redeeming_amount().unwrap_or_default(), + DispatchError::Corruption + ); + let post_state = pre_state.transition(RedeemTransition::DecreaseRedeemOrder(amount))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(amount) @@ -152,6 +155,8 @@ impl ForeignInvestment for Pallet { fn collect_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, + return_currency: T::CurrencyId, + pool_currency: T::CurrencyId, ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is // independent of the current `InvestState` @@ -160,9 +165,11 @@ impl ForeignInvestment for Pallet { amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; + let amount_currency_payout = + T::CurrencyConverter::pool_to_foreign(pool_currency, amount_payment, return_currency)?; + Ok(ExecutedForeignCollectInvest { - // TODO: Translate from `pool_currency` to `return_currency` - amount_currency_payout: amount_payment, + amount_currency_payout, amount_tranche_tokens_payout: amount_collected, }) } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 4a3c46038d..b5be443f8f 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -133,12 +133,12 @@ pub mod pallet { /// The default sell price limit for token swaps which defines the /// lowest acceptable buy price. /// - /// TODO(@review): Since we will only support stable coins from the - /// beginning, a global default value could be feasible or do we want to - /// have better granularity? - /// /// NOTE: Can be removed once we implement a /// more sophisticated swap price discovery. + // TODO(@review): Since we will only support stable coins from the + // beginning, a global default value could be feasible or do we want to + // have better granularity? + #[pallet::constant] type DefaultTokenSwapSellPriceLimit: Get; /// The default minimum fulfillment amount for token swaps. @@ -149,6 +149,10 @@ pub mod pallet { /// /// NOTE: Can be removed once we implement a more sophisticated swap /// price discovery. + // TODO(@review): Since we will only support stable coins from the + // beginning, a global default value could be feasible or do we want to + // have better granularity? + #[pallet::constant] type DefaultTokenMinFulfillmentAmount: Get; /// The token swap order identifying type @@ -182,6 +186,14 @@ pub mod pallet { Status = ExecutedForeignCollectRedeem, Error = DispatchError, >; + + /// Type which provides a conversion from one currency amount to another + /// currency amount. + type CurrencyConverter: cfg_traits::SimpleCurrencyConversion< + Balance = Self::Balance, + Currency = Self::CurrencyId, + Error = DispatchError, + >; } /// Maps an investor and their `InvestmentId` to the corresponding diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 5e5b5d397a..67289d1a27 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -294,11 +294,20 @@ where destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let currency_index_u128 = currency_index.index; + let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let pool_currency = + T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; let ExecutedForeignCollectInvest:: { amount_currency_payout, amount_tranche_tokens_payout, - } = T::ForeignInvestment::collect_foreign_investment(&investor, invest_id.clone())?; + } = T::ForeignInvestment::collect_foreign_investment( + &investor, + invest_id.clone(), + payment_currency, + pool_currency, + )?; T::Tokens::transfer( invest_id.into(), @@ -312,7 +321,7 @@ where pool_id, tranche_id, investor: investor.clone().into(), - currency: currency_index.index, + currency: currency_index_u128, currency_payout: amount_currency_payout, tranche_tokens_payout: amount_tranche_tokens_payout, }; diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 8e42a4f19b..678a28a8f1 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1340,13 +1340,16 @@ impl pallet_xcm_transactor::Config for Runtime { } parameter_types! { - // TODO: Discuss, refine + // TODO(@review): Discuss and refine all of these three parameters pub const DefaultTokenMinFulfillmentAmount: Balance = 1; pub const DefaultTokenSwapSellPriceLimit: Balance = 1; + pub ConversionRate: Rate = Rate::from((98, 100)); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; + type CurrencyConverter = + runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index a91986dde2..28c107cd6d 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -479,3 +479,78 @@ pub mod xcm_transactor { } } } + +pub mod foreign_investments { + use cfg_primitives::Balance; + use cfg_traits::SimpleCurrencyConversion; + use cfg_types::{ + fixed_point::{FixedPointNumberExtension, Rate}, + tokens::CurrencyId, + }; + use frame_support::pallet_prelude::PhantomData; + use sp_runtime::{traits::Get, DispatchError}; + + /// Simple stable coin amount converter from one stable to another. + /// + /// For now, converts any `ForeignAsset` into another with the configured + /// rate. + /// + /// NOTE: Should be deprecated ASAP! + // TODO(@review): Can we determine whether a ForeignAsset is a stable coin at + // this point of time? + pub struct SimpleStableCurrencyConverter(PhantomData); + + impl SimpleCurrencyConversion + for SimpleStableCurrencyConverter + where + RateForeignToPool: Get, + { + type Balance = Balance; + type Currency = CurrencyId; + type Error = DispatchError; + + fn foreign_to_pool( + currency_foreign: Self::Currency, + amount_foreign: Self::Balance, + currency_pool: Self::Currency, + ) -> Result { + match (currency_foreign, currency_pool) { + (out, inc) if out == inc => Ok(amount_foreign), + // TODO(future): Conversion must be limited to asset ids which reflect stable coins + (CurrencyId::ForeignAsset(_out_id), CurrencyId::ForeignAsset(_in_id)) => { + // NOTE: Rounding down to favor system side + RateForeignToPool::get() + .checked_mul_int_floor(amount_foreign) + .ok_or(DispatchError::Arithmetic( + sp_arithmetic::ArithmeticError::Overflow, + )) + } + _ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)), + } + } + + fn pool_to_foreign( + currency_foreign: Self::Currency, + amount_foreign: Self::Balance, + currency_pool: Self::Currency, + ) -> Result { + match (currency_foreign, currency_pool) { + (out, inc) if out == inc => Ok(amount_foreign), + // TODO(future): Conversion must be limited to asset ids which reflect stable coins + (CurrencyId::ForeignAsset(_out_id), CurrencyId::ForeignAsset(_in_id)) => { + // NOTE: Rounding down to favor system side + RateForeignToPool::get() + .reciprocal_floor() + .ok_or(DispatchError::Arithmetic( + sp_arithmetic::ArithmeticError::DivisionByZero, + ))? + .checked_mul_int_floor(amount_foreign) + .ok_or(DispatchError::Arithmetic( + sp_arithmetic::ArithmeticError::Overflow, + )) + } + _ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)), + } + } + } +} diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 29822fcd36..79801bd430 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1573,13 +1573,16 @@ impl orml_asset_registry::Config for Runtime { } parameter_types! { - // TODO: Discuss, refine + // TODO(@review): Discuss and refine all of these three parameters pub const DefaultTokenMinFulfillmentAmount: Balance = 1; pub const DefaultTokenSwapSellPriceLimit: Balance = 1; + pub ConversionRate: Rate = Rate::from((98, 100)); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; + type CurrencyConverter = + runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; From af301f3877165e11401cd780a3d3a60233209d24 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 17:11:35 +0200 Subject: [PATCH 31/96] refactor: add safety investing/redeeming checks --- .../foreign-investments/src/impls/invest.rs | 13 ++ pallets/foreign-investments/src/impls/mod.rs | 43 ++++- .../foreign-investments/src/impls/redeem.rs | 158 +++++++----------- 3 files changed, 106 insertions(+), 108 deletions(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 320a9984d2..747e4dcdb5 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -70,6 +70,19 @@ where InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => None, } } + + /// Returns the `invest_amount` if existent, else zero. + pub(crate) fn get_investing_amount(&self) -> Balance { + match *self { + InvestState::InvestmentOngoing { invest_amount} | + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { invest_amount, .. } | + InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { invest_amount, .. } | + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } | + InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } | + InvestState::SwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, + _ => Balance::zero() + } + } } // Actual impl of transition diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 732bf2ed9b..f6a54178d6 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -19,7 +19,7 @@ use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, Swap, }; -use frame_support::{traits::Get, transactional}; +use frame_support::{ensure, traits::Get, transactional}; use sp_runtime::{ traits::{EnsureAdd, EnsureAddAssign, Zero}, DispatchError, DispatchResult, @@ -87,12 +87,20 @@ impl ForeignInvestment for Pallet { pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + + // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be + // removed before deploying to production + let unprocessed_invest_amount = T::Investment::investment(&who, investment_id.clone())?; + ensure!( + unprocessed_invest_amount == pre_state.get_investing_amount(), + DispatchError::Corruption + ); + let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, currency_out: return_currency, amount, }))?; - Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) @@ -107,12 +115,20 @@ impl ForeignInvestment for Pallet { pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + + // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be + // removed before deploying to production + let unprocessed_invest_amount = T::Investment::investment(&who, investment_id.clone())?; + ensure!( + unprocessed_invest_amount == pre_state.get_investing_amount(), + DispatchError::Corruption + ); + let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { currency_in: pool_currency, currency_out: return_currency, amount, }))?; - Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) @@ -125,8 +141,16 @@ impl ForeignInvestment for Pallet { amount: T::Balance, ) -> Result<(), DispatchError> { let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount))?; + // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be + // removed before deploying to production + let unprocessed_redeem_amount = T::Investment::redemption(&who, investment_id.clone())?; + ensure!( + unprocessed_redeem_amount == pre_state.get_redeeming_amount(), + DispatchError::Corruption + ); + + let post_state = pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(()) @@ -138,10 +162,13 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { - let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id.clone())?; let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - frame_support::ensure!( - unprocessed_redeem_amount == pre_state.get_redeeming_amount().unwrap_or_default(), + + // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be + // removed before deploying to production + let unprocessed_redeem_amount = T::Investment::redemption(&who, investment_id.clone())?; + ensure!( + unprocessed_redeem_amount == pre_state.get_redeeming_amount(), DispatchError::Corruption ); @@ -403,7 +430,7 @@ impl Pallet { investment_id: T::InvestmentId, state: RedeemState, ) -> DispatchResult { - let invest_amount = state.get_invest_amount().unwrap_or_default(); + let invest_amount = state.get_invested_amount().unwrap_or_default(); // Do first round of updates and forward state as well as swap match state.clone() { diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 48f72facce..0eec3b9708 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -78,14 +78,11 @@ where } } - /// Returns the potentially existing redeeming amount of the inner state: - /// * If the inner state includes `Redeeming`, it returns the corresponding - /// `Some(amount)`. - /// * Else, it returns `None`. - pub(crate) fn get_redeeming_amount(&self) -> Option { + /// Returns the redeeming amount of the inner state, if existent. Else + /// returns zero. + pub(crate) fn get_redeeming_amount(&self) -> Balance { match self { - Self::NoState => None, - Self::Invested { .. } => None, + Self::NoState | Self::Invested { .. } => Balance::zero(), Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { inner.get_redeeming_amount() } @@ -94,7 +91,7 @@ where /// Returns the potentially existing invest, i.e. the upper redemption /// bound. - pub(crate) fn get_invest_amount(&self) -> Option { + pub(crate) fn get_invested_amount(&self) -> Option { match self { Self::Invested { invest_amount } | Self::InvestedAnd { invest_amount, .. } => { Some(*invest_amount) @@ -188,45 +185,30 @@ where /// * Else, it returns `None`. fn get_active_swap(&self) -> Option> { match *self { - Self::Redeeming { .. } => None, - Self::CollectableRedemption { .. } => None, - Self::RedeemingAndCollectableRedemption { .. } => None, - Self::ActiveSwapIntoReturnCurrency { swap } => Some(swap), - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), - Self::SwapIntoReturnDone { .. } => None, - Self::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), - Self::RedeemingAndSwapIntoReturnDone { .. } => None, - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), - Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { .. } => None, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Some(swap), - Self::CollectableRedemptionAndSwapIntoReturnDone { .. } => None, + Self::ActiveSwapIntoReturnCurrency { swap } | + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + Self::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } | + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | + Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + _ => None, } } - /// Returns the potentially existing redeeming amount: - /// * If the state includes `Redeeming`, it returns the corresponding - /// `Some(amount)`. - /// * Else, it returns `None`. - fn get_redeeming_amount(&self) -> Option { + /// Returns the redeeming amount if existent. Else returns zero. + fn get_redeeming_amount(&self) -> Balance { match *self { - Self::Redeeming { redeem_amount } => Some(redeem_amount), - Self::CollectableRedemption { .. } => None, - Self::RedeemingAndCollectableRedemption { redeem_amount, .. } => Some(redeem_amount), - Self::ActiveSwapIntoReturnCurrency { .. } => None, - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => None, - Self::SwapIntoReturnDone { .. } => None, - Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, .. } => Some(redeem_amount), - Self::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, .. } => Some(redeem_amount), - Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => Some(redeem_amount), - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } => None, - Self::CollectableRedemptionAndSwapIntoReturnDone { .. } => None, - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => None, + Self::Redeeming { redeem_amount } | + Self::RedeemingAndCollectableRedemption { redeem_amount, .. } | + Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, .. } | + Self::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } | + Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => redeem_amount, + _ => Balance::zero(), } } @@ -531,13 +513,6 @@ where // Edge case: if currency_in matches currency_out, we can immediately fulfill // the swap match *self { - Redeeming { .. } | - CollectableRedemption | - RedeemingAndCollectableRedemption { .. } | - SwapIntoReturnDone { .. } | - RedeemingAndSwapIntoReturnDone { .. } | - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { .. } | - CollectableRedemptionAndSwapIntoReturnDone { .. } => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), ActiveSwapIntoReturnCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) @@ -598,6 +573,7 @@ where Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) } }, + _ => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), } } @@ -633,14 +609,7 @@ where // A collectable redemption is considered to be _done_ iff the amount of pool // currency returned after calling `collect_redeem` is zero - match self.clone() { - Redeeming { .. } | - ActiveSwapIntoReturnCurrency { .. } | - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | - SwapIntoReturnDone { .. } | - RedeemingAndActiveSwapIntoReturnCurrency { .. } | - RedeemingAndSwapIntoReturnDone { .. } | - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), + match *self { CollectableRedemption => { if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) @@ -757,6 +726,7 @@ where }) } }, + state => Ok(state) } } @@ -774,19 +744,6 @@ where collected_swap: Swap, ) -> Result { match *self { - Redeeming { .. } | - ActiveSwapIntoReturnCurrency { .. } | - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | - SwapIntoReturnDone { .. } | - RedeemingAndActiveSwapIntoReturnCurrency { .. } | - RedeemingAndSwapIntoReturnDone { .. } | - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => Ok(*self), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } | - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } | - CollectableRedemptionAndActiveSwapIntoReturnCurrency { .. } | - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => { - Err(DispatchError::Other("Invalid pre state when transitioning collect for same currencies")) - }, CollectableRedemption => { if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) @@ -795,7 +752,7 @@ where done_swap: collected_swap, }) } - }, + } RedeemingAndCollectableRedemption { redeem_amount } => { if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) @@ -805,26 +762,27 @@ where done_swap: collected_swap, }) } - }, - - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => { - Ok(RedeemingAndSwapIntoReturnDone { - redeem_amount, - done_swap: Swap { - amount: done_swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - } - }) - }, - CollectableRedemptionAndSwapIntoReturnDone { done_swap } => { - Ok(SwapIntoReturnDone { - done_swap: Swap { - amount: done_swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - } - }) - }, + } + RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + redeem_amount, + done_swap, + } => Ok(RedeemingAndSwapIntoReturnDone { + redeem_amount, + done_swap: Swap { + amount: done_swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + }), + CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(SwapIntoReturnDone { + done_swap: Swap { + amount: done_swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }, + }), + _ => Err(DispatchError::Other( + "Invalid pre state when transitioning collect for same currencies", + )), } } } @@ -845,9 +803,6 @@ where /// * Else throws for incorrect pre state. fn handle_increase(&self, amount: Balance) -> Result { match self { - Self::NoState | Self::NotInvestedAnd { .. } => Err(DispatchError::Other( - "Invalid redeem state when transitioning an increase", - )), Self::Invested { invest_amount } => { if &amount == invest_amount { Ok(Self::NotInvestedAnd { @@ -879,6 +834,9 @@ where }) } } + _ => Err(DispatchError::Other( + "Invalid redeem state when transitioning an increase", + )), } } @@ -895,14 +853,14 @@ where )); match self.get_redeeming_amount() { - None => error_not_redeeming, + amount if amount.is_zero() => error_not_redeeming, // Can only decrease up to current redeeming amount - Some(redeem_amount) if redeem_amount <= amount => { + redeem_amount if redeem_amount <= amount => { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } // Entire redeeming amount becomes invested amount, i.e. remove `Redeeming` from inner // state - Some(redeem_amount) if redeem_amount == amount => match self { + redeem_amount if redeem_amount == amount => match self { Self::NoState | Self::Invested { .. } => error_not_redeeming, Self::NotInvestedAnd { inner } => match inner { Redeeming { .. } => Ok(Self::Invested { @@ -929,7 +887,7 @@ where }, // Partial redeeming amount becomes invested amount, i.e. keep `Redeeming` in inner // state - Some(old_redeem_amount) => { + old_redeem_amount => { let redeem_amount = old_redeem_amount.ensure_sub(amount)?; match self { @@ -959,9 +917,6 @@ where swap: Swap, ) -> Result { match self { - Self::NoState | Self::Invested { .. } => Err(DispatchError::Other( - "Invalid redeem state when transitioning a fulfilled order", - )), Self::NotInvestedAnd { inner } => Ok(Self::NotInvestedAnd { inner: inner.transition_fulfilled_swap_order(swap)?, }), @@ -972,6 +927,9 @@ where invest_amount: *invest_amount, inner: inner.transition_fulfilled_swap_order(swap)?, }), + _ => Err(DispatchError::Other( + "Invalid redeem state when transitioning a fulfilled order", + )), } } From c3b634e33bdea4a5d18a877859b34f4a6f6e905e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 17:53:59 +0200 Subject: [PATCH 32/96] refactor: remove TokenSwaps storage --- libs/types/src/investments.rs | 3 +- .../foreign-investments/src/impls/invest.rs | 6 +++ pallets/foreign-investments/src/impls/mod.rs | 39 ++++++++++------ .../foreign-investments/src/impls/redeem.rs | 3 -- pallets/foreign-investments/src/lib.rs | 45 +++++++++---------- pallets/liquidity-pools/src/hooks.rs | 10 +++-- 6 files changed, 60 insertions(+), 46 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index cadfd2c31a..1e9a07fe7e 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -156,9 +156,10 @@ pub struct CollectedAmount { /// NOTE: Trimmed version of `InvestmentInfo` required for foreign investments. #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] -pub struct ForeignInvestmentInfo { +pub struct ForeignInvestmentInfo { pub owner: AccountId, pub id: InvestmentId, + pub last_swap_reason: Option, } /// A simple representation of a currency swap. diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 747e4dcdb5..135506b753 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -577,6 +577,11 @@ where /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! + + // FIXME(@review): This handler assumes partial fulfillments and 1-to-1 + // conversion of amounts, i.e., 100 `return_currency` equals 100 + // `pool_currency`. If we use the CurrencyConverter, the amounts could be off as + // the `CurrencyConverter` is decoupled from the `TokenSwaps` trait. fn handle_fulfilled_swap_order( &self, swap: Swap, @@ -585,6 +590,7 @@ where InvestState::NoState | InvestState::InvestmentOngoing { .. } => Err(DispatchError::Other( "Invalid invest state when transitioning a fulfilled order", )), + // Increment ongoing investment by swapped amount InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, true)?; diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index f6a54178d6..68c36f3274 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -32,7 +32,6 @@ use crate::{ }, CollectedRedemptionTrancheTokens, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, - TokenSwapReasons, }; mod invest; @@ -52,7 +51,9 @@ impl StatusNotificationHook for Pallet { status: SwapOf, ) -> Result<(), DispatchError> { let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; - let reason = TokenSwapReasons::::get(id).ok_or(Error::::TokenSwapReasonNotFound)?; + let reason = info + .last_swap_reason + .ok_or(Error::::TokenSwapReasonNotFound)?; match reason { TokenSwapReason::Investment => { @@ -632,8 +633,8 @@ impl Pallet { /// updates an existing swap order. /// /// If the provided reason does not match the latest one stored in - /// `TokenSwapReasons`, also resolves the _merge conflict_ resulting from - /// updating and thus overwriting opposite swaps. See + /// `ForeignInvestmentInfo`, also resolves the _merge conflict_ resulting + /// from updating and thus overwriting opposite swaps. See /// [Self::handle_concurrent_swap_orders] for details. If this results in /// either an altered invest state and/or an altered redeem state, the /// corresponding storage is updated and the new states returned. The latter @@ -724,14 +725,12 @@ impl Pallet { if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { T::TokenSwaps::cancel_order(swap_order_id)?; ForeignInvestmentInfo::::remove(swap_order_id); - TokenSwapReasons::::remove(swap_order_id); } Ok(()) } /// Sets up `TokenSwapOrderIds` and `ForeignInvestmentInfo` storages, if the - /// order does not exist yet. Moreover, updates `TokenSwapReasons` pointer - /// to the provided value. + /// order does not exist yet. /// /// NOTE: Must only be called in `handle_swap_order`. #[transactional] @@ -754,10 +753,16 @@ impl Pallet { T::DefaultTokenSwapSellPriceLimit::get(), T::DefaultTokenMinFulfillmentAmount::get(), )?; - TokenSwapReasons::::insert(swap_order_id, reason); + ForeignInvestmentInfo::::insert( + swap_order_id, + ForeignInvestmentInfoOf:: { + owner: who.clone(), + id: investment_id, + last_swap_reason: Some(reason), + }, + ); } _ => { - // TODO: How to handle potential failure? let swap_order_id = T::TokenSwaps::place_order( who.clone(), swap.currency_out, @@ -772,9 +777,9 @@ impl Pallet { ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, + last_swap_reason: Some(reason), }, ); - TokenSwapReasons::::insert(swap_order_id, reason); } }; Ok(()) @@ -820,8 +825,10 @@ impl Pallet { ), DispatchError, > { - let last_reason = - TokenSwapReasons::::get(swap_order_id).ok_or(Error::::TokenSwapReasonNotFound)?; + let last_reason = ForeignInvestmentInfo::::get(swap_order_id) + .ok_or(Error::::ForeignInvestmentInfoNotFound)? + .last_swap_reason + .ok_or(Error::::TokenSwapReasonNotFound)?; // Exit early if both reasons match, i.e. we would not override any opposite // swap order @@ -954,9 +961,11 @@ impl Pallet { return_currency: T::CurrencyId, ) -> DispatchResult { T::ExecutedDecreaseInvestHook::notify_status_change( - ForeignInvestmentInfoOf:: { + cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), id: investment_id, + // not relevant here + last_swap_reason: None, }, ExecutedForeignDecrease { amount_decreased, @@ -976,9 +985,11 @@ impl Pallet { collected: CollectedAmount, ) -> DispatchResult { T::ExecutedCollectRedeemHook::notify_status_change( - ForeignInvestmentInfoOf:: { + cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), id: investment_id, + // not relevant here + last_swap_reason: None, }, ExecutedForeignCollectRedeem { currency, diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 0eec3b9708..8409acd9b8 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -591,9 +591,6 @@ where fn transition_collect( &self, collected_swap: Swap, - // TODO: Check whether we need to check this at another place, i.e. when transitioning - // redeem - // amount_unprocessed_redemption: Balance, ) -> Result { ensure!( self.get_active_swap() diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index b5be443f8f..58cd64b7fc 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -36,6 +36,7 @@ pub type SwapOf = Swap<::Balance, ::CurrencyId>; pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentInfo< ::AccountId, ::InvestmentId, + crate::types::TokenSwapReason, >; #[frame_support::pallet] @@ -53,7 +54,7 @@ pub mod pallet { }; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; - use types::{InvestState, RedeemState, TokenSwapReason}; + use types::{InvestState, RedeemState}; use super::*; @@ -175,14 +176,22 @@ pub mod pallet { /// The hook type which acts upon a finalized investment decrement. type ExecutedDecreaseInvestHook: StatusNotificationHook< - Id = ForeignInvestmentInfoOf, + Id = cfg_types::investments::ForeignInvestmentInfo< + Self::AccountId, + Self::InvestmentId, + (), + >, Status = ExecutedForeignDecrease, Error = DispatchError, >; /// The hook type which acts upon a finalized redemption collection. type ExecutedCollectRedeemHook: StatusNotificationHook< - Id = ForeignInvestmentInfoOf, + Id = cfg_types::investments::ForeignInvestmentInfo< + Self::AccountId, + Self::InvestmentId, + (), + >, Status = ExecutedForeignCollectRedeem, Error = DispatchError, >; @@ -237,12 +246,12 @@ pub mod pallet { RedeemState, >; - /// Maps `TokenSwapOrders` to `InvestmentInfo` to implicitly enable mapping - /// to `InvestmentState`. + /// Maps `TokenSwapOrders` to `ForeignInvestmentInfo` to implicitly enable + /// mapping to `InvestmentState` and `RedemptionState`. /// /// NOTE: The storage is immediately killed when the swap order is - /// completely fulfilled even if the investment might not be fully - /// processed. + /// completely fulfilled even if the corresponding investment and/or + /// redemption might not be fully processed. #[pallet::storage] pub(super) type ForeignInvestmentInfo = StorageMap<_, Blake2_128Concat, T::TokenSwapOrderId, ForeignInvestmentInfoOf>; @@ -281,23 +290,6 @@ pub mod pallet { ValueQuery, >; - /// Maps a `TokenSwapOrderId` to the corresponding `TokenSwapReason` for - /// which it was last updated, i.e. `Investment` or `Redemption`. - /// - /// As there can always be at most a single active token swap for any - /// `TokenSwapOrderId`, and thus also for any `(AccountId, InvestmentId)` - /// pair, we only need to keep track of the last reason when we act upon a - /// notified status update for any ongoing swap. Otherwise, it would be - /// impossible to know whether an invest or a redeem transition needs to be - /// applied. - /// - /// NOTE: The storage is immediately killed when the swap order is - /// completely fulfilled even if the investment might not be fully - /// processed. - #[pallet::storage] - pub(super) type TokenSwapReasons = - StorageMap<_, Blake2_128Concat, T::TokenSwapOrderId, TokenSwapReason>; - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -340,6 +332,11 @@ pub mod pallet { /// /// NOTE: We must ensure, this can practically never happen! TokenSwapReasonNotFound, + /// Failed to retrieve the `TokenSwapReason` from the given + /// `TokenSwapOrderId`. + /// + /// NOTE: We must ensure, this can practically never happen! + ForeignInvestmentInfoNotFound, // TODO: Not used at the moment /// Failed to determine whether the corresponding currency can be either /// used for payment or payout of an investment. diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index b8b19a5fd2..953e69b9b4 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -36,17 +36,18 @@ where ::AccountId: Into<[u8; 32]>, { type Error = DispatchError; - type Id = ForeignInvestmentInfo; + type Id = ForeignInvestmentInfo; type Status = ExecutedForeignDecrease; #[transactional] fn notify_status_change( - id: ForeignInvestmentInfo, + id: ForeignInvestmentInfo, status: ExecutedForeignDecrease, ) -> DispatchResult { let ForeignInvestmentInfo { id: investment_id, owner: investor, + .. } = id; let currency = Pallet::::try_get_general_index(status.return_currency)?; let wrapped_token = Pallet::::try_get_wrapped_token(&status.return_currency)?; @@ -73,17 +74,18 @@ where ::AccountId: Into<[u8; 32]>, { type Error = DispatchError; - type Id = ForeignInvestmentInfo; + type Id = ForeignInvestmentInfo; type Status = cfg_types::investments::ExecutedForeignCollectRedeem; #[transactional] fn notify_status_change( - id: ForeignInvestmentInfo, + id: ForeignInvestmentInfo, status: cfg_types::investments::ExecutedForeignCollectRedeem, ) -> DispatchResult { let ForeignInvestmentInfo { id: investment_id, owner: investor, + .. } = id; let currency = Pallet::::try_get_general_index(status.currency)?; let wrapped_token = Pallet::::try_get_wrapped_token(&status.currency)?; From d9d0246aaff0eb154c02804298e1dbd6876afcfc Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 18:03:21 +0200 Subject: [PATCH 33/96] feat: add orderbook to altair runtime --- Cargo.lock | 1 + runtime/altair/Cargo.toml | 5 + runtime/altair/src/lib.rs | 26 ++++- runtime/altair/src/weights/mod.rs | 1 + .../altair/src/weights/pallet_order_book.rs | 103 ++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 runtime/altair/src/weights/pallet_order_book.rs diff --git a/Cargo.lock b/Cargo.lock index ea2fb73af5..f24e08ac4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,6 +257,7 @@ dependencies = [ "pallet-migration-manager", "pallet-multisig", "pallet-nft-sales", + "pallet-order-book", "pallet-permissions", "pallet-pool-registry", "pallet-pool-system", diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index b7696991ef..b22d581620 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -122,6 +122,7 @@ pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway pallet-loans = { path = "../../pallets/loans", default-features = false } pallet-migration-manager = { path = "../../pallets/migration", default-features = false } pallet-nft-sales = { path = "../../pallets/nft-sales", default-features = false } +pallet-order-book = { path = "../../pallets/order-book", default-features = false } pallet-permissions = { path = "../../pallets/permissions", default-features = false } pallet-pool-registry = { path = "../../pallets/pool-registry", default-features = false } pallet-pool-system = { path = "../../pallets/pool-system", default-features = false } @@ -197,6 +198,8 @@ std = [ "pallet-multisig/std", "pallet-membership/std", "pallet-nft-sales/std", + "pallet-order-book/std", + "pallet-permissions/std", "pallet-permissions/std", "moonbeam-relay-encoder/std", "pallet-pool-system/std", @@ -281,6 +284,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-nft-sales/runtime-benchmarks", + "pallet-order-book/runtime-benchmarks", "pallet-permissions/runtime-benchmarks", "pallet-pool-system/runtime-benchmarks", "pallet-pool-registry/runtime-benchmarks", @@ -368,6 +372,7 @@ try-runtime = [ "pallet-multisig/try-runtime", "pallet-membership/try-runtime", "pallet-nft-sales/try-runtime", + "pallet-order-book/try-runtime", "pallet-permissions/try-runtime", "pallet-pool-system/try-runtime", "pallet-pool-registry/try-runtime", diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 678a28a8f1..266e95668c 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1709,6 +1709,27 @@ impl pallet_keystore::pallet::Config for Runtime { type WeightInfo = (); } +parameter_types! { + pub const OrderBookCreationFeeKey: FeeKey = FeeKey::OrderBookOrderCreation; + pub const OrderPairVecSize: u32 = 1_000_000u32; +} + +impl pallet_order_book::Config for Runtime { + type AssetCurrencyId = CurrencyId; + type AssetRegistry = OrmlAssetRegistry; + type FeeCurrencyId = NativeToken; + type Fees = Fees; + type ForeignCurrencyBalance = Balance; + type FulfilledOrderHook = ForeignInvestments; + type OrderFeeKey = OrderBookCreationFeeKey; + type OrderIdNonce = u64; + type OrderPairVecSize = OrderPairVecSize; + type ReserveCurrency = Balances; + type RuntimeEvent = RuntimeEvent; + type TradeableAsset = OrmlTokens; + type Weights = weights::pallet_order_book::WeightInfo; +} + // Frame Order in this block dictates the index of each one in the metadata // Any addition should be done at the bottom // Any deletion affects the following frames during runtime upgrades @@ -1771,7 +1792,8 @@ construct_runtime!( PriceCollector: pallet_data_collector::{Pallet, Storage} = 107, LiquidityPools: pallet_liquidity_pools::{Pallet, Call, Storage, Event} = 108, LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 109, - ForeignInvestments: pallet_foreign_investments::{Pallet, Call, Storage, Event} = 110, + OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 110, + ForeignInvestments: pallet_foreign_investments::{Pallet, Call, Storage, Event} = 111, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, @@ -2342,6 +2364,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_session, SessionBench::); list_benchmark!(list, extra, pallet_restricted_tokens, Tokens); list_benchmark!(list, extra, pallet_keystore, Keystore); + list_benchmark!(list, extra, pallet_order_book, OrderBook); let storage_info = AllPalletsWithSystem::storage_info(); @@ -2412,6 +2435,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_session, SessionBench::); add_benchmark!(params, batches, pallet_restricted_tokens, Tokens); add_benchmark!(params, batches, pallet_keystore, Keystore); + add_benchmark!(params, batches, pallet_order_book, OrderBook); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/altair/src/weights/mod.rs b/runtime/altair/src/weights/mod.rs index 47b5b4bff2..33f0831ef5 100644 --- a/runtime/altair/src/weights/mod.rs +++ b/runtime/altair/src/weights/mod.rs @@ -27,6 +27,7 @@ pub mod pallet_loans; pub mod pallet_migration_manager; pub mod pallet_multisig; pub mod pallet_nft_sales; +pub mod pallet_order_book; pub mod pallet_permissions; pub mod pallet_pool_registry; pub mod pallet_pool_system; diff --git a/runtime/altair/src/weights/pallet_order_book.rs b/runtime/altair/src/weights/pallet_order_book.rs new file mode 100644 index 0000000000..39ad8d28d3 --- /dev/null +++ b/runtime/altair/src/weights/pallet_order_book.rs @@ -0,0 +1,103 @@ + +//! Autogenerated weights for `pallet_order_book` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Theas-MacBook-Pro.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 + +// Executed Command: +// /Users/thealeake/centrifuge-repos/centrifuge-chain/target/release/centrifuge-chain +// benchmark +// pallet +// --chain=development-local +// --steps=50 +// --repeat=20 +// --pallet=pallet_order_book +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/pallet_order_book.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_order_book`. +pub struct WeightInfo(PhantomData); +impl pallet_order_book::WeightInfo for WeightInfo { + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrderBook NonceStore (r:1 w:1) + /// Proof: OrderBook NonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Storage: OrderBook Orders (r:0 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + fn create_order_v1() -> Weight { + // Proof Size summary in bytes: + // Measured: `1585` + // Estimated: `32017313` + // Minimum execution time: 57_000 nanoseconds. + Weight::from_parts(58_000_000, 32017313) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + fn user_cancel_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1570` + // Estimated: `32012984` + // Minimum execution time: 49_000 nanoseconds. + Weight::from_parts(52_000_000, 32012984) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrmlTokens Accounts (r:4 w:4) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + fn fill_order_full() -> Weight { + // Proof Size summary in bytes: + // Measured: `2449` + // Estimated: `32030798` + // Minimum execution time: 92_000 nanoseconds. + Weight::from_parts(93_000_000, 32030798) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} From fa31b2a98ec38106196c5917cc1af28da6aa3c68 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 18:04:12 +0200 Subject: [PATCH 34/96] refactor: cleanup boilerplate files --- .../foreign-investments/src/benchmarking.rs | 48 ------------- pallets/foreign-investments/src/lib.rs | 10 --- pallets/foreign-investments/src/mock.rs | 72 ------------------- pallets/foreign-investments/src/tests.rs | 40 ----------- 4 files changed, 170 deletions(-) delete mode 100644 pallets/foreign-investments/src/benchmarking.rs delete mode 100644 pallets/foreign-investments/src/mock.rs delete mode 100644 pallets/foreign-investments/src/tests.rs diff --git a/pallets/foreign-investments/src/benchmarking.rs b/pallets/foreign-investments/src/benchmarking.rs deleted file mode 100644 index 60d5e4efad..0000000000 --- a/pallets/foreign-investments/src/benchmarking.rs +++ /dev/null @@ -1,48 +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. - -// //! Benchmarking setup for pallet-template -// #![cfg(feature = "runtime-benchmarks")] -// use super::*; - -// #[allow(unused)] -// use crate::Pallet as Template; -// use frame_benchmarking::v2::*; -// use frame_system::RawOrigin; - -// #[benchmarks] -// mod benchmarks { -// use super::*; - -// #[benchmark] -// fn do_something() { -// let value = 100u32.into(); -// let caller: T::AccountId = whitelisted_caller(); -// #[extrinsic_call] -// do_something(RawOrigin::Signed(caller), value); - -// assert_eq!(Something::::get(), Some(value)); -// } - -// #[benchmark] -// fn cause_error() { -// Something::::put(100u32); -// let caller: T::AccountId = whitelisted_caller(); -// #[extrinsic_call] -// cause_error(RawOrigin::Signed(caller)); - -// assert_eq!(Something::::get(), Some(101u32)); -// } - -// impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); -// } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 58cd64b7fc..ff3c991e95 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -13,16 +13,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -// #[cfg(test)] -// mod mock; - -// #[cfg(test)] -// mod tests; - -// #[cfg(feature = "runtime-benchmarks")] -// mod benchmarking; -// pub mod weights; -// pub use weights::*; use cfg_types::investments::Swap; /// Edit this file to define custom logic or remove it if it is not needed. /// Learn more about FRAME and the core library of Substrate FRAME pallets: diff --git a/pallets/foreign-investments/src/mock.rs b/pallets/foreign-investments/src/mock.rs deleted file mode 100644 index d847608fb4..0000000000 --- a/pallets/foreign-investments/src/mock.rs +++ /dev/null @@ -1,72 +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 crate as pallet_template; -// use frame_support::traits::{ConstU16, ConstU64}; -// use sp_core::H256; -// use sp_runtime::{ -// testing::Header, -// traits::{BlakeTwo256, IdentityLookup}, -// }; - -// type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -// type Block = frame_system::mocking::MockBlock; - -// // Configure a mock runtime to test the pallet. -// frame_support::construct_runtime!( -// pub enum Test where -// Block = Block, -// NodeBlock = Block, -// UncheckedExtrinsic = UncheckedExtrinsic, -// { -// System: frame_system, -// TemplateModule: pallet_template, -// } -// ); - -// impl frame_system::Config for Test { -// type BaseCallFilter = frame_support::traits::Everything; -// type BlockWeights = (); -// type BlockLength = (); -// type DbWeight = (); -// type RuntimeOrigin = RuntimeOrigin; -// type RuntimeCall = RuntimeCall; -// type Index = u64; -// type BlockNumber = u64; -// type Hash = H256; -// type Hashing = BlakeTwo256; -// type AccountId = u64; -// type Lookup = IdentityLookup; -// type Header = Header; -// type RuntimeEvent = RuntimeEvent; -// type BlockHashCount = ConstU64<250>; -// type Version = (); -// type PalletInfo = PalletInfo; -// type AccountData = (); -// type OnNewAccount = (); -// type OnKilledAccount = (); -// type SystemWeightInfo = (); -// type SS58Prefix = ConstU16<42>; -// type OnSetCode = (); -// type MaxConsumers = frame_support::traits::ConstU32<16>; -// } - -// impl pallet_template::Config for Test { -// type RuntimeEvent = RuntimeEvent; -// type WeightInfo = (); -// } - -// // Build genesis storage according to the mock runtime. -// pub fn new_test_ext() -> sp_io::TestExternalities { -// frame_system::GenesisConfig::default().build_storage::().unwrap().into() -// } diff --git a/pallets/foreign-investments/src/tests.rs b/pallets/foreign-investments/src/tests.rs deleted file mode 100644 index 74fc626f65..0000000000 --- a/pallets/foreign-investments/src/tests.rs +++ /dev/null @@ -1,40 +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 crate::{mock::*, Error, Event}; -// use frame_support::{assert_noop, assert_ok}; - -// #[test] -// fn it_works_for_default_value() { -// new_test_ext().execute_with(|| { -// // Go past genesis block so events get deposited -// System::set_block_number(1); -// // Dispatch a signed extrinsic. -// assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); -// // Read pallet storage and assert an expected result. -// assert_eq!(TemplateModule::something(), Some(42)); -// // Assert that the correct event was deposited -// System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); -// }); -// } - -// #[test] -// fn correct_error_for_none_value() { -// new_test_ext().execute_with(|| { -// // Ensure the expected error is thrown when no value is present. -// assert_noop!( -// TemplateModule::cause_error(RuntimeOrigin::signed(1)), -// Error::::NoneValue -// ); -// }); -// } From b43121313ef67bb0b6f6591d7c074cf8239860b9 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 18:05:15 +0200 Subject: [PATCH 35/96] fix: swap direction check --- libs/types/src/investments.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 1e9a07fe7e..c56fbb9095 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -201,15 +201,13 @@ impl DispatchResult { if is_same_swap_direction - && self.currency_in != other.currency_in - && self.currency_out != other.currency_out + && (self.currency_in != other.currency_in || self.currency_out != other.currency_out) { Err(DispatchError::Other( "Swap currency mismatch for same swap direction", )) } else if !is_same_swap_direction - && self.currency_in != other.currency_out - && self.currency_out != other.currency_in + && (self.currency_in != other.currency_out || self.currency_out != other.currency_in) { Err(DispatchError::Other( "Swap currency mismatch for opposite swap direction", From 99789f15280d6936584500ea9ad8c05dff582a22 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 18:07:17 +0200 Subject: [PATCH 36/96] refactor: FI extrinsics --- pallets/foreign-investments/src/lib.rs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index ff3c991e95..459b6832f9 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -38,10 +38,7 @@ pub mod pallet { use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, }; - use frame_support::{ - dispatch::HasCompact, - pallet_prelude::{DispatchResultWithPostInfo, *}, - }; + use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; use types::{InvestState, RedeemState}; @@ -346,14 +343,13 @@ pub mod pallet { /// /// NOOP: If the unprocessed investment amount is zero or the state does /// not include `InvestmentOngoing` - // TODO: weights/benchmark, numbers chosen by rough estimation #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] #[pallet::call_index(1)] pub fn nudge_invest_state( origin: OriginFor, investor: T::AccountId, investment_id: T::InvestmentId, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { ensure_signed(origin)?; if let Some(invest_state) = InvestmentState::::get(&investor, investment_id) { @@ -363,11 +359,8 @@ pub mod pallet { types::InvestTransition::EpochExecution(amount_unprocessed_investment), )?; Pallet::::apply_invest_state_transition(&investor, investment_id, new_state)?; - - Ok(Some(T::DbWeight::get().reads_writes(5, 5)).into()) - } else { - Ok(Some(T::DbWeight::get().reads(1)).into()) } + Ok(()) } /// Attempts to transition a `RedeemState` after an epoch execution: @@ -379,14 +372,13 @@ pub mod pallet { /// /// NOOP: If the unprocessed redemption amount is zero or the inner /// state does not include `Redeeming`. - // TODO: weights/benchmark, numbers chosen by rough estimation #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] #[pallet::call_index(2)] pub fn nudge_redeem_state( origin: OriginFor, investor: T::AccountId, investment_id: T::InvestmentId, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { ensure_signed(origin)?; if let Some(redeem_state) = RedemptionState::::get(&investor, investment_id) { @@ -396,11 +388,9 @@ pub mod pallet { types::RedeemTransition::EpochExecution(amount_unprocessed_redemption), )?; Pallet::::apply_redeem_state_transition(&investor, investment_id, new_state)?; - - Ok(Some(T::DbWeight::get().reads_writes(5, 5)).into()) - } else { - Ok(Some(T::DbWeight::get().reads(1)).into()) } + + Ok(()) } } } From 7342690ebe2d53ec99c07ee20198ee648bf6abfb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 21:06:20 +0200 Subject: [PATCH 37/96] feat: improve error handling --- pallets/foreign-investments/src/errors.rs | 34 ++++++++ pallets/foreign-investments/src/impls/mod.rs | 81 ++++++++++++++------ pallets/foreign-investments/src/lib.rs | 59 +++++++++----- 3 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 pallets/foreign-investments/src/errors.rs diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs new file mode 100644 index 0000000000..6f812d9a67 --- /dev/null +++ b/pallets/foreign-investments/src/errors.rs @@ -0,0 +1,34 @@ +// 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 codec::{Decode, Encode}; +use frame_support::PalletError; +use scale_info::TypeInfo; + +#[derive(Encode, Decode, TypeInfo, PalletError)] +pub enum InvestError { + Increase, + Decrease, + FulfillSwapOrder, + EpochExecution, +} + +#[derive(Encode, Decode, TypeInfo, PalletError)] + +pub enum RedeemError { + Increase, + Collect, + Decrease, + EpochExecution, + FulfillSwapOrder, +} diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 68c36f3274..92b4ef7dd9 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -26,6 +26,7 @@ use sp_runtime::{ }; use crate::{ + errors::{InvestError, RedeemError}, types::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, @@ -58,14 +59,24 @@ impl StatusNotificationHook for Pallet { match reason { TokenSwapReason::Investment => { let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); - let post_state = - pre_state.transition(InvestTransition::FulfillSwapOrder(status))?; + let post_state = pre_state + .transition(InvestTransition::FulfillSwapOrder(status)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(InvestError::FulfillSwapOrder) + })?; Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) } TokenSwapReason::Redemption => { let pre_state = RedemptionState::::get(&info.owner, info.id).unwrap_or_default(); - let post_state = - pre_state.transition(RedeemTransition::FulfillSwapOrder(status))?; + let post_state = pre_state + .transition(RedeemTransition::FulfillSwapOrder(status)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(RedeemError::FulfillSwapOrder) + })?; Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) } } @@ -97,11 +108,17 @@ impl ForeignInvestment for Pallet { DispatchError::Corruption ); - let post_state = pre_state.transition(InvestTransition::IncreaseInvestOrder(Swap { - currency_in: pool_currency, - currency_out: return_currency, - amount, - }))?; + let post_state = pre_state + .transition(InvestTransition::IncreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + amount, + })) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("InvestState transition error: {:?}", e); + Error::::from(InvestError::Increase) + })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) @@ -125,11 +142,17 @@ impl ForeignInvestment for Pallet { DispatchError::Corruption ); - let post_state = pre_state.transition(InvestTransition::DecreaseInvestOrder(Swap { - currency_in: pool_currency, - currency_out: return_currency, - amount, - }))?; + let post_state = pre_state + .transition(InvestTransition::DecreaseInvestOrder(Swap { + currency_in: pool_currency, + currency_out: return_currency, + amount, + })) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("InvestState transition error: {:?}", e); + Error::::from(InvestError::Decrease) + })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) @@ -151,7 +174,13 @@ impl ForeignInvestment for Pallet { DispatchError::Corruption ); - let post_state = pre_state.transition(RedeemTransition::IncreaseRedeemOrder(amount))?; + let post_state = pre_state + .transition(RedeemTransition::IncreaseRedeemOrder(amount)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("RedeemState transition error: {:?}", e); + Error::::from(RedeemError::Increase) + })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(()) @@ -173,7 +202,9 @@ impl ForeignInvestment for Pallet { DispatchError::Corruption ); - let post_state = pre_state.transition(RedeemTransition::DecreaseRedeemOrder(amount))?; + let post_state = pre_state + .transition(RedeemTransition::DecreaseRedeemOrder(amount)) + .map_err(|_| Error::::from(RedeemError::Decrease))?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(amount) @@ -218,11 +249,17 @@ impl ForeignInvestment for Pallet { // Transition state to initiate swap from pool to return currency let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); - let post_state = pre_state.transition(RedeemTransition::Collect(SwapOf:: { - amount: collected.amount_collected, - currency_in: return_currency, - currency_out: pool_currency, - }))?; + let post_state = pre_state + .transition(RedeemTransition::Collect(SwapOf:: { + amount: collected.amount_collected, + currency_in: return_currency, + currency_out: pool_currency, + })) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("RedeemState transition error: {:?}", e); + Error::::from(RedeemError::Collect) + })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -826,7 +863,7 @@ impl Pallet { DispatchError, > { let last_reason = ForeignInvestmentInfo::::get(swap_order_id) - .ok_or(Error::::ForeignInvestmentInfoNotFound)? + .ok_or(Error::::InvestmentInfoNotFound)? .last_swap_reason .ok_or(Error::::TokenSwapReasonNotFound)?; diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 459b6832f9..cf28a37bf3 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -19,6 +19,7 @@ use cfg_types::investments::Swap; /// pub use pallet::*; +pub mod errors; pub mod impls; pub mod types; @@ -38,6 +39,7 @@ pub mod pallet { use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, }; + use errors::{InvestError, RedeemError}; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; @@ -303,33 +305,42 @@ pub mod pallet { #[pallet::error] // TODO: Add more errors pub enum Error { - /// Failed to retrieve the `InvestmentInfo` from the given - /// `TokenSwapOrderId`. - /// - /// NOTE: We must ensure, this can practically never happen! - InvestmentInfoNotFound, // TODO: Not used at the moment /// Failed to retrieve the `RedemptionInfo` from the given /// `TokenSwapOrderId`. /// /// NOTE: We must ensure, this can practically never happen! RedemptionInfoNotFound, - /// Failed to retrieve the `TokenSwapReason` from the given - /// `TokenSwapOrderId`. + // TODO: Not used at the moment + /// Failed to determine whether the corresponding currency can be either + /// used for payment or payout of an investment. /// /// NOTE: We must ensure, this can practically never happen! - TokenSwapReasonNotFound, + InvalidInvestmentCurrency, /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. /// /// NOTE: We must ensure, this can practically never happen! - ForeignInvestmentInfoNotFound, - // TODO: Not used at the moment - /// Failed to determine whether the corresponding currency can be either - /// used for payment or payout of an investment. + InvestmentInfoNotFound, + /// Failed to retrieve the `TokenSwapReason` from the given + /// `TokenSwapOrderId`. /// /// NOTE: We must ensure, this can practically never happen! - InvalidInvestmentCurrency, + TokenSwapReasonNotFound, + InvestError(InvestError), + RedeemError(RedeemError), + } + + impl From for Error { + fn from(error: InvestError) -> Self { + Error::::InvestError(error) + } + } + + impl From for Error { + fn from(error: RedeemError) -> Self { + Error::::RedeemError(error) + } } #[pallet::call] @@ -355,9 +366,14 @@ pub mod pallet { if let Some(invest_state) = InvestmentState::::get(&investor, investment_id) { let amount_unprocessed_investment = T::Investment::investment(&investor, investment_id)?; - let new_state = invest_state.transition( - types::InvestTransition::EpochExecution(amount_unprocessed_investment), - )?; + let new_state = invest_state + .transition(types::InvestTransition::EpochExecution( + amount_unprocessed_investment, + )) + .map_err(|e| { + log::debug!("InvestState transition error: {:?}", e); + Error::::from(InvestError::EpochExecution) + })?; Pallet::::apply_invest_state_transition(&investor, investment_id, new_state)?; } Ok(()) @@ -384,9 +400,14 @@ pub mod pallet { if let Some(redeem_state) = RedemptionState::::get(&investor, investment_id) { let amount_unprocessed_redemption = T::Investment::redemption(&investor, investment_id)?; - let new_state = redeem_state.transition( - types::RedeemTransition::EpochExecution(amount_unprocessed_redemption), - )?; + let new_state = redeem_state + .transition(types::RedeemTransition::EpochExecution( + amount_unprocessed_redemption, + )) + .map_err(|e| { + log::debug!("RedeemState transition error: {:?}", e); + Error::::from(RedeemError::EpochExecution) + })?; Pallet::::apply_redeem_state_transition(&investor, investment_id, new_state)?; } From f8351cf90cd25f36d8ec912e94cce56fcd4a8145 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 21:52:21 +0200 Subject: [PATCH 38/96] fix: clippy --- libs/test-utils/src/mocks/order_manager.rs | 2 +- .../foreign-investments/src/impls/invest.rs | 574 +++++++++--------- pallets/foreign-investments/src/impls/mod.rs | 44 +- .../foreign-investments/src/impls/redeem.rs | 20 +- pallets/foreign-investments/src/types.rs | 116 ++-- pallets/liquidity-pools/src/inbound.rs | 10 +- 6 files changed, 398 insertions(+), 368 deletions(-) diff --git a/libs/test-utils/src/mocks/order_manager.rs b/libs/test-utils/src/mocks/order_manager.rs index cecd3c38e5..6070249d6a 100644 --- a/libs/test-utils/src/mocks/order_manager.rs +++ b/libs/test-utils/src/mocks/order_manager.rs @@ -14,7 +14,7 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { - use cfg_traits::{ + use cfg_traits::investments::{ Investment, InvestmentAccountant, InvestmentProperties, OrderManager, TrancheCurrency, }; use cfg_types::orders::{FulfillmentWithPrice, TotalOrder}; diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 135506b753..4f51fb9a8f 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -11,6 +11,8 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use core::cmp::Ordering; + use cfg_types::investments::Swap; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, @@ -34,13 +36,13 @@ where transition: InvestTransition, ) -> Result { match transition { - InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(&self, swap), - InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(&self, swap), + InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(self, swap), + InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(self, swap), InvestTransition::FulfillSwapOrder(swap) => { - Self::handle_fulfilled_swap_order(&self, swap) + Self::handle_fulfilled_swap_order(self, swap) } InvestTransition::EpochExecution(amount_unprocessed) => { - Self::handle_epoch_execution(&self, amount_unprocessed) + Self::handle_epoch_execution(self, amount_unprocessed) } } } @@ -135,7 +137,7 @@ where /// this can never occur! fn handle_increase(&self, swap: Swap) -> Result { if swap.currency_in == swap.currency_out { - return Self::handle_increase_non_foreign(&self, swap); + return Self::handle_increase_non_foreign(self, swap); } match &self { @@ -164,40 +166,40 @@ where let invest_amount = swap.amount.min(return_swap.amount); let done_amount = swap.amount.min(return_swap.amount); - // pool swap amount is immediately invested and done amount increased equally - if swap.amount < return_swap.amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + match swap.amount.cmp(&return_swap.amount) { + // pool swap amount is immediately invested and done amount increased equally + Ordering::Equal => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) - } - // swap amount is immediately invested and done amount increased equally - else if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + ) + } + // swap amount is immediately invested and done amount increased equally + Ordering::Less => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: *return_swap, invest_amount, - }) - } - // return swap amount is immediately invested and done amount increased equally - else { - Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, - ..swap + }), + // return swap amount is immediately invested and done amount increased equally + Ordering::Greater => { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) + ) + } } } // Bump pool swap @@ -226,40 +228,40 @@ where invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; let done_amount = swap.amount.min(return_swap.amount); - // pool swap amount is immediately invested and done amount increased equally - if swap.amount < return_swap.amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + match swap.amount.cmp(&return_swap.amount) { + // pool swap amount is immediately invested and done amount increased equally + Ordering::Equal => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) - } - // swap amount is immediately invested and done amount increased equally - else if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + ) + } + // swap amount is immediately invested and done amount increased equally + Ordering::Less => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: *return_swap, invest_amount, - }) - } - // return swap amount is immediately invested and done amount increased equally - else { - Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, - ..swap + }), + // return swap amount is immediately invested and done amount increased equally + Ordering::Greater => { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) + ) + } } } // Reduce amount of return by the increasing amount and increase investing as well as @@ -273,42 +275,42 @@ where let done_amount = invest_amount.ensure_add(*done_amount)?; // pool swap amount is immediately invested and done amount increased equally - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + match swap.amount.cmp(&return_swap.amount) { + Ordering::Equal => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, ..*return_swap }, invest_amount, - }) - } - // swap amount is immediately invested and done amount increased equally - else if swap.amount < return_swap.amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + }), + // swap amount is immediately invested and done amount increased equally + Ordering::Less => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount < return_swap.amount + amount: return_swap.amount - swap.amount, + ..*return_swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) - } - // return swap amount is immediately invested and done amount increased equally - else { - Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, - ..swap + ) + } + // return swap amount is immediately invested and done amount increased equally + Ordering::Greater => { + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe since swap.amount > return_swap.amount + amount: swap.amount - return_swap.amount, + ..swap + }, + done_amount, + invest_amount, }, - done_amount, - invest_amount, - }, - ) + ) + } } } // Reduce amount of return swap by increasing amount and increase investing as well as @@ -326,19 +328,17 @@ where .min(return_swap.amount) .ensure_add(*done_amount)?; - // pool swap amount is immediately invested and done amount increased equally - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + match swap.amount.cmp(&return_swap.amount) { + // pool swap amount is immediately invested and done amount increased equally + Ordering::Equal => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, ..*return_swap }, invest_amount, - }) - } - // swap amount is immediately invested and done amount increased equally - else if swap.amount < return_swap.amount { - Ok( + }), + // swap amount is immediately invested and done amount increased equally + Ordering::Less => Ok( Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { // safe since swap.amount < return_swap.amount @@ -348,11 +348,9 @@ where done_amount, invest_amount, }, - ) - } - // return swap amount is immediately invested and done amount increased equally - else { - Ok( + ), + // return swap amount is immediately invested and done amount increased equally + Ordering::Greater => Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap: Swap { // safe since swap.amount > return_swap.amount @@ -362,7 +360,7 @@ where done_amount, invest_amount, }, - ) + ), } } _ => Err(DispatchError::Other( @@ -396,7 +394,7 @@ where /// this can never occur! fn handle_decrease(&self, swap: Swap) -> Result { if swap.currency_in == swap.currency_out { - return Self::handle_decrease_non_foreign(&self, swap); + return Self::handle_decrease_non_foreign(self, swap); } match &self { @@ -408,38 +406,44 @@ where }, // Increment return swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { - if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap, - invest_amount: *invest_amount - swap.amount, - }) - } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrency { swap }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + match swap.amount.cmp(invest_amount) { + Ordering::Less => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap, + invest_amount: *invest_amount - swap.amount, + }) + }, + Ordering::Equal => { + Ok(Self::ActiveSwapIntoReturnCurrency { swap }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } } }, // Increment return done amount up to amount of the active pool swap InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, false)?; - if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDone { done_swap: swap }) - } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { - swap: Swap { - // safe because swap.amount < pool_swap.amount - amount: pool_swap.amount - swap.amount, - ..*pool_swap - }, - done_amount: swap.amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + match swap.amount.cmp(&pool_swap.amount) { + Ordering::Equal => { + Ok(Self::SwapIntoReturnDone { done_swap: swap }) + }, + Ordering::Less => { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because swap.amount < pool_swap.amount + amount: pool_swap.amount - swap.amount, + ..*pool_swap + }, + done_amount: swap.amount, + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } } }, // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment @@ -504,20 +508,23 @@ where swap.ensure_currencies_match(return_swap, true)?; let amount = return_swap.amount.ensure_add(swap.amount)?; - if swap.amount < *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap: Swap { amount, ..swap }, - // safe because invest_amount > swap_amount - invest_amount: *invest_amount - swap.amount, - }) - } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrency { - swap: Swap { amount, ..swap }, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + match swap.amount.cmp(invest_amount) { + Ordering::Less => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + swap: Swap { amount, ..swap }, + // safe because invest_amount > swap_amount + invest_amount: *invest_amount - swap.amount, + }) + }, + Ordering::Equal => { + Ok(Self::ActiveSwapIntoReturnCurrency { + swap: Swap { amount, ..swap }, + }) + }, + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + }, } }, InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { @@ -528,24 +535,27 @@ where swap.ensure_currencies_match(return_swap, true)?; let amount = return_swap.amount.ensure_add(swap.amount)?; - if swap.amount < *invest_amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + match swap.amount.cmp(invest_amount) { + Ordering::Less => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { amount, ..swap }, + done_amount: *done_amount, + // safe because swap.amount < invest_amount + invest_amount: *invest_amount - swap.amount, + }, + ) + }, + Ordering::Equal => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount, ..swap }, done_amount: *done_amount, - // safe because swap.amount < invest_amount - invest_amount: *invest_amount - swap.amount, - }, - ) - } else if swap.amount == *invest_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { amount, ..swap }, - done_amount: *done_amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) + } } }, _ => Err(DispatchError::Other( @@ -595,44 +605,50 @@ where InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, true)?; - if swap.amount == pool_swap.amount { - Ok(Self::InvestmentOngoing { - invest_amount: swap.amount, - }) - } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, - ..swap - }, - invest_amount: swap.amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + match swap.amount.cmp(&pool_swap.amount) { + Ordering::Equal => { + Ok(Self::InvestmentOngoing { + invest_amount: swap.amount, + }) + }, + Ordering::Less => { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, + ..swap + }, + invest_amount: swap.amount, + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, // Increment done_return by swapped amount InvestState::ActiveSwapIntoReturnCurrency { swap: return_swap } => { swap.ensure_currencies_match(return_swap, true)?; - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDone { done_swap: swap }) - } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, - done_amount: swap.amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + match swap.amount.cmp(&return_swap.amount) { + Ordering::Equal => { + Ok(Self::SwapIntoReturnDone { done_swap: swap }) + } + Ordering::Less => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount: swap.amount, + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, // Increment ongoing investment by swapped amount @@ -643,21 +659,24 @@ where swap.ensure_currencies_match(pool_swap, true)?; let invest_amount = invest_amount.ensure_add(swap.amount)?; - if swap.amount == pool_swap.amount { - Ok(Self::InvestmentOngoing { invest_amount }) - } else if swap.amount < pool_swap.amount { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, - ..swap - }, - invest_amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + match swap.amount.cmp(&pool_swap.amount) { + Ordering::Equal => { + Ok(Self::InvestmentOngoing { invest_amount }) + }, + Ordering::Less => { + Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + // safe because pool_swap.amount > swap.amount + amount: pool_swap.amount - swap.amount, + ..swap + }, + invest_amount, + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, // Increment done_return by swapped amount, leave invest amount untouched @@ -667,27 +686,30 @@ where } => { swap.ensure_currencies_match(return_swap, true)?; - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - done_swap: swap, - invest_amount: *invest_amount, - }) - } else if swap.amount < return_swap.amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, - done_amount: swap.amount, + match swap.amount.cmp(&return_swap.amount) { + Ordering::Equal => { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap: swap, invest_amount: *invest_amount, - }, - ) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + }) + } + Ordering::Less => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount: swap.amount, + invest_amount: *invest_amount, + }, + ) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, // Increment done_return by swapped amount @@ -698,26 +720,29 @@ where swap.ensure_currencies_match(return_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDone { - done_swap: Swap { - amount: done_amount, - ..swap - }, - }) - } else if swap.amount < return_swap.amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, - ..swap - }, - done_amount, - }) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + match swap.amount.cmp(&return_swap.amount) { + Ordering::Equal => { + Ok(Self::SwapIntoReturnDone { + done_swap: Swap { + amount: done_amount, + ..swap + }, + }) + } + Ordering::Less => { + Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount, + }) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, // Increment done_return by swapped amount, leave invest amount untouched @@ -729,30 +754,33 @@ where swap.ensure_currencies_match(return_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; - if swap.amount == return_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - done_swap: Swap { - amount: done_amount, - ..swap - }, - invest_amount: *invest_amount, - }) - } else if swap.amount < return_swap.amount { - Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, + match swap.amount.cmp(&return_swap.amount) { + Ordering::Equal => { + Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + done_swap: Swap { + amount: done_amount, ..swap }, - done_amount, invest_amount: *invest_amount, - }, - ) - } - // should never occur but let's be safe here - else { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + }) + } + Ordering::Less => { + Ok( + Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + swap: Swap { + // safe because return_swap.amount > swap.amount + amount: return_swap.amount - swap.amount, + ..swap + }, + done_amount, + invest_amount: *invest_amount, + }, + ) + } + // should never occur but let's be safe here + Ordering::Greater => { + Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) + } } }, _ => Err(DispatchError::Other( diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 92b4ef7dd9..564e0d0b1d 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -98,11 +98,11 @@ impl ForeignInvestment for Pallet { return_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production - let unprocessed_invest_amount = T::Investment::investment(&who, investment_id.clone())?; + let unprocessed_invest_amount = T::Investment::investment(who, investment_id)?; ensure!( unprocessed_invest_amount == pre_state.get_investing_amount(), DispatchError::Corruption @@ -132,11 +132,11 @@ impl ForeignInvestment for Pallet { return_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_state = InvestmentState::::get(who, investment_id.clone()).unwrap_or_default(); + let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production - let unprocessed_invest_amount = T::Investment::investment(&who, investment_id.clone())?; + let unprocessed_invest_amount = T::Investment::investment(who, investment_id)?; ensure!( unprocessed_invest_amount == pre_state.get_investing_amount(), DispatchError::Corruption @@ -164,11 +164,11 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result<(), DispatchError> { - let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production - let unprocessed_redeem_amount = T::Investment::redemption(&who, investment_id.clone())?; + let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id)?; ensure!( unprocessed_redeem_amount == pre_state.get_redeeming_amount(), DispatchError::Corruption @@ -192,11 +192,11 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { - let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production - let unprocessed_redeem_amount = T::Investment::redemption(&who, investment_id.clone())?; + let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id)?; ensure!( unprocessed_redeem_amount == pre_state.get_redeeming_amount(), DispatchError::Corruption @@ -248,7 +248,7 @@ impl ForeignInvestment for Pallet { })?; // Transition state to initiate swap from pool to return currency - let pre_state = RedemptionState::::get(who, investment_id.clone()).unwrap_or_default(); + let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); let post_state = pre_state .transition(RedeemTransition::Collect(SwapOf:: { amount: collected.amount_collected, @@ -350,14 +350,14 @@ impl Pallet { state: InvestState, ) -> DispatchResult { // Do first round of updates and forward state, swap as well as invest amount - match state.clone() { + match state { InvestState::NoState => { InvestmentState::::remove(who, investment_id); Ok((InvestState::NoState, None, Zero::zero())) }, InvestState::InvestmentOngoing { invest_amount } => { - InvestmentState::::insert(who, investment_id, state.clone()); + InvestmentState::::insert(who, investment_id, state); Ok((state, None, invest_amount)) }, @@ -365,21 +365,21 @@ impl Pallet { InvestState::ActiveSwapIntoReturnCurrency { swap } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { - InvestmentState::::insert(who, investment_id, state.clone()); + InvestmentState::::insert(who, investment_id, state); Ok((state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into return is fulfilled InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { - InvestmentState::::insert(who, investment_id, state.clone()); + InvestmentState::::insert(who, investment_id, state); Ok((state, Some(swap), invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; - InvestmentState::::insert(who, investment_id, new_state.clone()); + InvestmentState::::insert(who, investment_id, new_state); Ok((new_state, Some(swap), Zero::zero())) }, @@ -387,7 +387,7 @@ impl Pallet { Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; - InvestmentState::::insert(who, investment_id, new_state.clone()); + InvestmentState::::insert(who, investment_id, new_state); Ok((new_state, Some(swap), invest_amount)) }, @@ -402,7 +402,7 @@ impl Pallet { Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount, done_swap.currency_in)?; let new_state = InvestState::InvestmentOngoing { invest_amount }; - InvestmentState::::insert(who, investment_id, new_state.clone()); + InvestmentState::::insert(who, investment_id, new_state); Ok((new_state, None, invest_amount)) }, @@ -471,7 +471,7 @@ impl Pallet { let invest_amount = state.get_invested_amount().unwrap_or_default(); // Do first round of updates and forward state as well as swap - match state.clone() { + match state { RedeemState::NoState => { RedemptionState::::remove(who, investment_id); Ok((Some(RedeemState::NoState), None)) @@ -595,7 +595,8 @@ impl Pallet { /// event can be deposited /// * `Some(state)` indicates a `ForeignRedemptionUpdated` event can be /// deposited - /// * `None` indicates no state mutation occurred /// + /// * `None` indicates no state mutation occurred + #[allow(clippy::type_complexity)] #[transactional] fn apply_collect_redeem_transition( who: &T::AccountId, @@ -678,6 +679,7 @@ impl Pallet { /// is required for emitting events. /// /// NOTE: Must not call any other swap order updating function. + #[allow(clippy::type_complexity)] #[transactional] fn handle_swap_order( who: &T::AccountId, @@ -712,7 +714,7 @@ impl Pallet { if let Some(InvestState::NoState) = maybe_invest_state { *current_invest_state = None; } else if maybe_invest_state != *current_invest_state { - *current_invest_state = maybe_invest_state.clone(); + *current_invest_state = maybe_invest_state; } }); @@ -890,7 +892,7 @@ impl Pallet { invest_swap_amount.max(redeem_swap_amount) - resolved_amount; // Determine new invest state - let new_invest_state = match invest_state.clone() { + let new_invest_state = match invest_state { // As redeem swap can only be into return currency, we need to delta on the opposite // swap directions InvestState::ActiveSwapIntoPoolCurrency { swap } => { @@ -937,7 +939,7 @@ impl Pallet { .map_err(|e: DispatchError| e)?; // Determine final swap amount and new redeem state - let (final_swap_amount, new_redeem_state) = match invest_state.clone() { + let (final_swap_amount, new_redeem_state) = match invest_state { // Opposite swaps cancel out at least one (or if equal amounts) both swaps InvestState::ActiveSwapIntoPoolCurrency { .. } | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } => { diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 8409acd9b8..5bd83b80da 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -51,14 +51,14 @@ where transition: RedeemTransition, ) -> Result { match transition { - RedeemTransition::IncreaseRedeemOrder(amount) => Self::handle_increase(&self, amount), - RedeemTransition::DecreaseRedeemOrder(amount) => Self::handle_decrease(&self, amount), + RedeemTransition::IncreaseRedeemOrder(amount) => Self::handle_increase(self, amount), + RedeemTransition::DecreaseRedeemOrder(amount) => Self::handle_decrease(self, amount), RedeemTransition::FulfillSwapOrder(swap) => { - Self::handle_fulfilled_swap_order(&self, swap) + Self::handle_fulfilled_swap_order(self, swap) } - RedeemTransition::Collect(swap) => Self::handle_collect(&self, swap), + RedeemTransition::Collect(swap) => Self::handle_collect(self, swap), RedeemTransition::EpochExecution(amount_unprocessed) => { - Self::handle_epoch_execution(&self, amount_unprocessed) + Self::handle_epoch_execution(self, amount_unprocessed) } } } @@ -133,7 +133,7 @@ where ) -> Result { match self { Self::InvestedAnd { inner, .. } | Self::NotInvestedAnd { inner } => Ok( - Self::swap_inner_state(&self, inner.fulfill_active_swap_amount(amount)?), + Self::swap_inner_state(self, inner.fulfill_active_swap_amount(amount)?), ), _ => Err(DispatchError::Other( "Cannot alter active swap amount for RedeemStates without swap", @@ -437,7 +437,7 @@ where /// * Else throws. fn add_or_overwrite_redeem_amount(&self, amount: Balance) -> Result { if amount.is_zero() { - return Self::remove_redeem_amount(&self); + return Self::remove_redeem_amount(self); } match *self { Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), @@ -463,7 +463,7 @@ where /// Throws if the the state does not include `Redeeming`. fn set_existing_redeem_amount(&self, amount: Balance) -> Result { if amount.is_zero() { - return Self::remove_redeem_amount(&self); + return Self::remove_redeem_amount(self); } match *self { Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), @@ -601,7 +601,7 @@ where ); if collected_swap.currency_in == collected_swap.currency_out { - return Self::transition_collect_non_foreign(&self, collected_swap); + return Self::transition_collect_non_foreign(self, collected_swap); } // A collectable redemption is considered to be _done_ iff the amount of pool @@ -943,7 +943,7 @@ where "Invalid redeem state when transitioning collect", )), RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( - Self::swap_inner_state(&self, inner.transition_collect(swap)?), + Self::swap_inner_state(self, inner.transition_collect(swap)?), ), } } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index b7ca1ee843..856e5eafc4 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -61,24 +61,24 @@ pub enum InvestState< ActiveSwapIntoReturnCurrency { swap: Swap }, /// The investment is not fully swapped into pool currency and thus split /// into two parts: - /// * One part is still being swapped. - /// * The remainder is already waiting to be processed as investment. + /// * One part is still being swapped. + /// * The remainder is already waiting to be processed as investment. ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap, invest_amount: Balance, }, /// The investment is split into two parts: - /// * One part is waiting to be processed as investment. - /// * The remainder is swapped back into the return currency as a result - /// of decreasing the invested amount before being processed. + /// * One part is waiting to be processed as investment. + /// * The remainder is swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap: Swap, invest_amount: Balance, }, /// The investment is split into two parts: - /// * The one part is swapping into pool currency. - /// * The remainder was swapped back into the return currency as a - /// result of decreasing the invested amount before being processed. + /// * The one part is swapping into pool currency. + /// * The remainder was swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into `ActiveSwapIntoPoolCurrency` /// by applying the corresponding trigger to handle the return amount. @@ -93,10 +93,10 @@ pub enum InvestState< done_amount: Balance, }, /// The investment is split into three parts: - /// * One part is currently swapping into the pool currency. - /// * The second is already waiting to be processed as investment. - /// * The remainder was swapped back into the return currency as a - /// result of decreasing the invested amount before being processed. + /// * One part is currently swapping into the pool currency. + /// * The second is already waiting to be processed as investment. + /// * The remainder was swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` by applying the @@ -107,10 +107,10 @@ pub enum InvestState< invest_amount: Balance, }, /// The investment is split into three parts: - /// * One is waiting to be processed as investment. - /// * The second is swapped back into the return currency as a result of - /// decreasing the invested amount before being processed. - /// * The remainder was already swapped back into the return currency. + /// * One is waiting to be processed as investment. + /// * The second is swapped back into the return currency as a result of + /// decreasing the invested amount before being processed. + /// * The remainder was already swapped back into the return currency. /// /// NOTE: This state should not be transitioned by applying the trigger for /// the done part but wait until the active swap is fulfilled. @@ -125,9 +125,9 @@ pub enum InvestState< /// handle the return amount. SwapIntoReturnDone { done_swap: Swap }, /// The investment is split into two parts: - /// * One part is waiting to be processed as an investment - /// * The swapped back into the return currency as a result of - /// decreasing the invested amount before being processed. + /// * One part is waiting to be processed as an investment + /// * The swapped back into the return currency as a result of decreasing + /// the invested amount before being processed. /// /// NOTE: This state can be transitioned into `InvestmentOngoing` by /// applying the corresponding trigger to handle the return amount. @@ -151,10 +151,10 @@ pub enum InvestTransition< DecreaseInvestOrder(Swap), /// Implicitly derives `swap.currency_in` and `swap.currency_out` from /// previous state: - /// * If the previous state includes `ActiveSwapIntoPoolCurrency`, - /// `currency_in` is the pool currency. - /// * If the previous state includes `ActiveSwapIntoReturnCurrency`, - /// `currency_in` is the return currency. + /// * If the previous state includes `ActiveSwapIntoPoolCurrency`, + /// `currency_in` is the pool currency. + /// * If the previous state includes `ActiveSwapIntoReturnCurrency`, + /// `currency_in` is the return currency. FulfillSwapOrder(Swap), EpochExecution(Balance), } @@ -224,8 +224,8 @@ pub enum InnerRedeemState< ActiveSwapIntoReturnCurrency { swap: Swap }, /// The redemption was fully processed, collected and partially swapped into /// the return currency. It is split into two parts: - /// * One part is swapping back into the return currency. - /// * The remainder was already swapped back. + /// * One part is swapping back into the return currency. + /// * The remainder was already swapped back. ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap, done_amount: Balance, @@ -238,75 +238,75 @@ pub enum InnerRedeemState< /// similar to the corresponding state in `InvestState`. SwapIntoReturnDone { done_swap: Swap }, /// The redemption is split into two parts: - /// * One part is waiting to be processed as redemption. - /// * The remainder is swapping back into the return currency as a - /// result of processing and collecting beforehand. + /// * One part is waiting to be processed as redemption. + /// * The remainder is swapping back into the return currency as a result of + /// processing and collecting beforehand. RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: Balance, swap: Swap, }, /// The redemption is split into two parts: - /// * One part is waiting to be processed as redemption. - /// * The remainder is swapping back into the return currency as a - /// result of processing and collecting beforehand. + /// * One part is waiting to be processed as redemption. + /// * The remainder is swapping back into the return currency as a result of + /// processing and collecting beforehand. RedeemingAndSwapIntoReturnDone { redeem_amount: Balance, done_swap: Swap, }, /// The redemption is split into three parts: - /// * One part is waiting to be processed as redemption. - /// * The second is swapping back into the return currency as a result - /// of processing and collecting beforehand. - /// * The remainder was already swapped back. + /// * One part is waiting to be processed as redemption. + /// * The second is swapping back into the return currency as a result of + /// processing and collecting beforehand. + /// * The remainder was already swapped back. RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: Balance, swap: Swap, done_amount: Balance, }, /// The redemption is split into three parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The remainder is swapping back into the return currency as a - /// result of processing and collecting beforehand. + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The remainder is swapping back into the return currency as a result of + /// processing and collecting beforehand. RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: Balance, swap: Swap, }, /// The redemption is split into three parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The remainder was successfully swapped back into the return - /// currency as a result of processing and collecting beforehand. + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The remainder was successfully swapped back into the return currency + /// as a result of processing and collecting beforehand. RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: Balance, done_swap: Swap, }, /// The redemption is split into four parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The third part is swapping back into the return currency as a result - /// of processing and collecting beforehand - /// * The remainder was already swapped back. + /// * One part is waiting to be processed as redemption. + /// * The second is waiting to be collected. + /// * The third part is swapping back into the return currency as a result + /// of processing and collecting beforehand + /// * The remainder was already swapped back. RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: Balance, swap: Swap, done_amount: Balance, }, /// The redemption is split into two parts: - /// * One part is waiting to be collected. - /// * The remainder is swapping back into the return currency as a - /// result of processing and collecting beforehand. + /// * One part is waiting to be collected. + /// * The remainder is swapping back into the return currency as a result of + /// processing and collecting beforehand. CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap: Swap }, /// The redemption is split into two parts: - /// * One part is waiting to be collected. - /// * The remainder was successfully swapped back into the return - /// currency as a result of processing and collecting beforehand. + /// * One part is waiting to be collected. + /// * The remainder was successfully swapped back into the return currency + /// as a result of processing and collecting beforehand. CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap }, /// The redemption is split into three parts: - /// * One part is waiting to be collected. - /// * The second is swapping back into the return currency as a result of - /// processing and collecting beforehand - /// * The remainder was already swapped back. + /// * One part is waiting to be collected. + /// * The second is swapping back into the return currency as a result of + /// processing and collecting beforehand + /// * The remainder was already swapped back. CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap, done_amount: Balance, diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 67289d1a27..baf69579bb 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -104,7 +104,7 @@ where let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; let pool_currency = - T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; + T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; // Mint additional amount of payment currency T::Tokens::mint_into(payment_currency, &investor, amount)?; @@ -139,7 +139,7 @@ where let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; let pool_currency = - T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; + T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; T::ForeignInvestment::decrease_foreign_investment( &investor, @@ -243,7 +243,7 @@ where tranche_id, investor: investor.clone().into(), currency: currency_index.index, - tranche_tokens_payout: tranche_tokens_payout, + tranche_tokens_payout, }; T::OutboundQueue::submit(investor, destination.domain(), message)?; @@ -297,7 +297,7 @@ where let currency_index_u128 = currency_index.index; let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; let pool_currency = - T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; + T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; let ExecutedForeignCollectInvest:: { amount_currency_payout, @@ -351,7 +351,7 @@ where let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; let pool_currency = - T::PoolInspect::currency_for(pool_id).ok_or_else(|| Error::::PoolNotFound)?; + T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; T::ForeignInvestment::collect_foreign_redemption( &investor, From 6f7abb1c65165b3082ce108d801f76a3f3500fdd Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 22:13:09 +0200 Subject: [PATCH 39/96] fix: unit tests --- libs/test-utils/src/mocks/accountant.rs | 4 +-- pallets/foreign-investments/src/impls/mod.rs | 2 ++ pallets/investments/src/mock.rs | 2 +- pallets/order-book/src/mock.rs | 19 ++++++++++++- pallets/order-book/src/tests.rs | 30 ++++++++++---------- pallets/pool-registry/src/benchmarking.rs | 2 +- pallets/pool-registry/src/mock.rs | 4 ++- pallets/pool-system/src/benchmarking.rs | 5 +++- pallets/pool-system/src/impls.rs | 2 +- pallets/pool-system/src/mock.rs | 4 +-- pallets/pool-system/src/tests/mod.rs | 2 +- 11 files changed, 50 insertions(+), 26 deletions(-) diff --git a/libs/test-utils/src/mocks/accountant.rs b/libs/test-utils/src/mocks/accountant.rs index ff759426ce..6fe086b481 100644 --- a/libs/test-utils/src/mocks/accountant.rs +++ b/libs/test-utils/src/mocks/accountant.rs @@ -105,7 +105,7 @@ macro_rules! impl_mock_accountant { pub payment_currency: $currency_id, } - impl cfg_traits::InvestmentAccountant<$account_id> for $name + 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> @@ -166,7 +166,7 @@ macro_rules! impl_mock_accountant { } } - impl cfg_traits::InvestmentProperties<$account_id> for InvestmentInfo { + impl cfg_traits::investments::InvestmentProperties<$account_id> for InvestmentInfo { type Currency = $currency_id; type Id = $investment_id; diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 564e0d0b1d..d8a61e4dd3 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -10,6 +10,7 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +#![allow(clippy::map_identity)] use cfg_traits::{ investments::{ForeignInvestment, Investment, InvestmentCollector}, @@ -851,6 +852,7 @@ impl Pallet { /// into the opposite direction, i.e. `ActiveSwapIntoReturnCurrency`, we /// need to resolve the delta between both swap order amounts and update /// the states accordingly. + #[allow(clippy::type_complexity)] fn handle_concurrent_swap_orders( who: &T::AccountId, investment_id: T::InvestmentId, diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index 16813c101d..a137d1a682 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -15,7 +15,7 @@ use std::ops::Add; pub use cfg_primitives::CFG as CURRENCY; use cfg_primitives::*; -use cfg_traits::{OrderManager, PreConditions}; +use cfg_traits::{investments::OrderManager, PreConditions}; use cfg_types::{ fixed_point::Rate, investments::InvestmentAccount, diff --git a/pallets/order-book/src/mock.rs b/pallets/order-book/src/mock.rs index b66dfa2b08..0e7b69e396 100644 --- a/pallets/order-book/src/mock.rs +++ b/pallets/order-book/src/mock.rs @@ -11,8 +11,13 @@ // GNU General Public License for more details. use cfg_mocks::pallet_mock_fees; -use cfg_types::tokens::{CurrencyId, CustomMetadata}; +use cfg_traits::StatusNotificationHook; +use cfg_types::{ + investments::Swap, + tokens::{CurrencyId, CustomMetadata}, +}; use frame_support::{ + pallet_prelude::DispatchResult, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild}, }; @@ -145,6 +150,17 @@ parameter_types! { pub const OrderPairVecSize: u32 = 1_000_000u32; } +pub struct DummyHook; +impl StatusNotificationHook for DummyHook { + type Error = sp_runtime::DispatchError; + type Id = u64; + type Status = Swap; + + fn notify_status_change(_id: u64, _status: Self::Status) -> DispatchResult { + Ok(()) + } +} + impl order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = RegistryMock; @@ -152,6 +168,7 @@ impl order_book::Config for Runtime { // type Balance = Balance; type Fees = Fees; type ForeignCurrencyBalance = ForeignCurrencyBalance; + type FulfilledOrderHook = DummyHook; type OrderFeeKey = OrderFeeKey; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index c83eca4422..7723c42867 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -26,7 +26,7 @@ fn create_order_v1_works() { buy_amount: 100, initial_buy_amount: 100, price: 10, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, max_sell_amount: 1000 }) ); @@ -40,7 +40,7 @@ fn create_order_v1_works() { buy_amount: 100, initial_buy_amount: 100, price: 10, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, max_sell_amount: 1000 }) ); @@ -110,7 +110,7 @@ fn user_cancel_order_only_works_for_valid_account() { buy_amount: 100, initial_buy_amount: 100, price: 10, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, max_sell_amount: 1000 }) ); @@ -283,7 +283,7 @@ fn place_order_works() { buy_amount: 100, initial_buy_amount: 100, price: 10, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, max_sell_amount: 1000 }) ); @@ -298,7 +298,7 @@ fn place_order_works() { buy_amount: 100, initial_buy_amount: 100, price: 10, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, max_sell_amount: 1000 }) ); @@ -331,7 +331,7 @@ fn place_order_works() { currency_in: CurrencyId::AUSD, currency_out: CurrencyId::ForeignAsset(0), buy_amount: 100, - min_fullfillment_amount: 100, + min_fulfillment_amount: 100, sell_price_limit: 10 }) ); @@ -360,7 +360,7 @@ fn place_order_consolidates_reserve_when_fee_matches_out() { buy_amount: 10, initial_buy_amount: 10, price: 2, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, max_sell_amount: 20 }) ); @@ -381,7 +381,7 @@ fn place_order_consolidates_reserve_when_fee_matches_out() { currency_in: CurrencyId::ForeignAsset(0), currency_out: CurrencyId::Native, buy_amount: 10, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, sell_price_limit: 2 }) ); @@ -560,7 +560,7 @@ fn update_order_works() { buy_amount: 110, initial_buy_amount: 100, price: 20, - min_fullfillment_amount: 110, + min_fulfillment_amount: 110, max_sell_amount: 2200 }) ); @@ -575,7 +575,7 @@ fn update_order_works() { buy_amount: 110, initial_buy_amount: 100, price: 20, - min_fullfillment_amount: 110, + min_fulfillment_amount: 110, max_sell_amount: 2200 }) ); @@ -604,7 +604,7 @@ fn update_order_works() { order_id, account: ACCOUNT_0, buy_amount: 110, - min_fullfillment_amount: 110, + min_fulfillment_amount: 110, sell_price_limit: 20 }) ); @@ -634,7 +634,7 @@ fn update_order_consolidates_reserve_increase_when_asset_out_fee_currency() { buy_amount: 10, initial_buy_amount: 10, price: 3, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, max_sell_amount: 30 }) ); @@ -660,7 +660,7 @@ fn update_order_consolidates_reserve_increase_when_asset_out_fee_currency() { order_id, account: ACCOUNT_0, buy_amount: 10, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, sell_price_limit: 3 }) ); @@ -690,7 +690,7 @@ fn update_order_consolidates_reserve_decrease_when_asset_out_fee_currency() { buy_amount: 10, initial_buy_amount: 10, price: 1, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, max_sell_amount: 10 }) ); @@ -716,7 +716,7 @@ fn update_order_consolidates_reserve_decrease_when_asset_out_fee_currency() { order_id, account: ACCOUNT_0, buy_amount: 10, - min_fullfillment_amount: 10, + min_fulfillment_amount: 10, sell_price_limit: 1 }) ); diff --git a/pallets/pool-registry/src/benchmarking.rs b/pallets/pool-registry/src/benchmarking.rs index f2db3fe643..9bcfbf0613 100644 --- a/pallets/pool-registry/src/benchmarking.rs +++ b/pallets/pool-registry/src/benchmarking.rs @@ -13,7 +13,7 @@ //! Module provides benchmarking for Loan Pallet use cfg_primitives::{Moment, PoolEpochId}; -use cfg_traits::{InvestmentAccountant, InvestmentProperties, TrancheCurrency as _}; +use cfg_traits::investments::{InvestmentAccountant, InvestmentProperties, TrancheCurrency as _}; use cfg_types::{ pools::TrancheMetadata, tokens::{CurrencyId, TrancheCurrency}, diff --git a/pallets/pool-registry/src/mock.rs b/pallets/pool-registry/src/mock.rs index aab5e2623f..5821864081 100644 --- a/pallets/pool-registry/src/mock.rs +++ b/pallets/pool-registry/src/mock.rs @@ -12,7 +12,9 @@ use std::marker::PhantomData; use cfg_primitives::{BlockNumber, CollectionId, Moment, PoolEpochId, TrancheWeight}; -use cfg_traits::{OrderManager, PoolMutate, PoolUpdateGuard, PreConditions, UpdateState}; +use cfg_traits::{ + investments::OrderManager, PoolMutate, PoolUpdateGuard, PreConditions, UpdateState, +}; use cfg_types::{ fixed_point::Rate, permissions::{PermissionScope, Role}, diff --git a/pallets/pool-system/src/benchmarking.rs b/pallets/pool-system/src/benchmarking.rs index 254599e3dc..b4b5f44c15 100644 --- a/pallets/pool-system/src/benchmarking.rs +++ b/pallets/pool-system/src/benchmarking.rs @@ -13,7 +13,10 @@ //! Module provides benchmarking for Loan Pallet use cfg_primitives::PoolEpochId; -use cfg_traits::{InvestmentAccountant, InvestmentProperties, TrancheCurrency as _, UpdateState}; +use cfg_traits::{ + investments::{InvestmentAccountant, InvestmentProperties, TrancheCurrency as _}, + UpdateState, +}; use cfg_types::{ pools::TrancheMetadata, tokens::{CurrencyId, CustomMetadata, TrancheCurrency}, diff --git a/pallets/pool-system/src/impls.rs b/pallets/pool-system/src/impls.rs index 487a871bee..0c16a88a86 100644 --- a/pallets/pool-system/src/impls.rs +++ b/pallets/pool-system/src/impls.rs @@ -446,7 +446,7 @@ impl ChangeGuard for Pallet { #[cfg(feature = "runtime-benchmarks")] mod benchmarks_utils { - use cfg_traits::{Investment, PoolBenchmarkHelper}; + use cfg_traits::{investments::Investment, PoolBenchmarkHelper}; use cfg_types::{ pools::TrancheMetadata, tokens::{CurrencyId, CustomMetadata}, diff --git a/pallets/pool-system/src/mock.rs b/pallets/pool-system/src/mock.rs index 084db51249..dcdf60201e 100644 --- a/pallets/pool-system/src/mock.rs +++ b/pallets/pool-system/src/mock.rs @@ -12,8 +12,8 @@ use cfg_primitives::{Balance, BlockNumber, CollectionId, PoolId, TrancheId}; pub use cfg_primitives::{Moment, PoolEpochId, TrancheWeight}; use cfg_traits::{ - OrderManager, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, - TrancheCurrency as TrancheCurrencyT, + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + Permissions as PermissionsT, PoolUpdateGuard, PreConditions, }; pub use cfg_types::fixed_point::Rate; use cfg_types::{ diff --git a/pallets/pool-system/src/tests/mod.rs b/pallets/pool-system/src/tests/mod.rs index b42d87ed33..4749994567 100644 --- a/pallets/pool-system/src/tests/mod.rs +++ b/pallets/pool-system/src/tests/mod.rs @@ -10,7 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{PoolMutate, TrancheCurrency as TrancheCurrencyT, TrancheTokenPrice}; +use cfg_traits::{PoolMutate, investments::TrancheCurrency as TrancheCurrencyT, TrancheTokenPrice}; use cfg_types::{ epoch::EpochState, fixed_point::Rate, From 6d5351e79a76ed0341a49ba4196ff97a81460d44 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 18 Aug 2023 22:27:45 +0200 Subject: [PATCH 40/96] fix: compile runtime integrations --- .../pallet/development/tests/liquidity_pools.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 1c8ae419cc..7eaf5bf314 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -29,13 +29,14 @@ use ::xcm::{ }; use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId}; use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::{Codec, InboundQueue}, - OrderManager, Permissions as _, PoolMutate, TrancheCurrency, + Permissions as _, PoolMutate, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, fixed_point::Rate, - investments::InvestmentAccount, + investments::{InvestCollection, InvestmentAccount, RedeemCollection}, orders::FulfillmentWithPrice, permissions::{PermissionScope, PoolRole, Role, UNION}, pools::TrancheMetadata, @@ -59,6 +60,7 @@ use frame_support::{ use hex::FromHex; use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_investments::CollectOutcome; use pallet_liquidity_pools::{ encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, }; @@ -1305,6 +1307,7 @@ fn inbound_collect_invest_order() { pool_id, tranche_id: default_tranche_id(pool_id), investor: investor.clone().into(), + currency: general_currency_index(currency_id), }; // Execute byte message @@ -1364,11 +1367,11 @@ fn inbound_collect_invest_order() { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), processed_orders: vec![0], who: investor.clone(), - collection: pallet_investments::InvestCollection:: { + collection: InvestCollection:: { payout_investment_invest: amount, remaining_investment_invest: 0, }, - outcome: pallet_investments::CollectOutcome::FullyCollected, + outcome: CollectOutcome::FullyCollected, } .into() })); @@ -1542,6 +1545,7 @@ fn inbound_collect_redeem_order() { pool_id, tranche_id: default_tranche_id(pool_id), investor: investor.clone().into(), + currency: general_currency_index(currency_id), }; // Execute byte message @@ -1595,11 +1599,11 @@ fn inbound_collect_redeem_order() { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), processed_orders: vec![0], who: investor.clone(), - collection: pallet_investments::RedeemCollection:: { + collection: RedeemCollection:: { payout_investment_redeem: amount, remaining_investment_redeem: 0, }, - outcome: pallet_investments::CollectOutcome::FullyCollected, + outcome: CollectOutcome::FullyCollected, } .into() })); From d1d50bed5fc2ff240ea87021322887b45760c2ef Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Sun, 20 Aug 2023 10:01:40 +0200 Subject: [PATCH 41/96] refactor: fix simple currency conversion --- libs/traits/src/lib.rs | 17 +++----- pallets/foreign-investments/src/impls/mod.rs | 2 +- runtime/common/src/lib.rs | 42 +++++--------------- 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index dcb2f1355e..54ef5855c6 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -532,18 +532,11 @@ pub trait SimpleCurrencyConversion { type Balance; type Error; - /// Estimate the worth of a foreign stable currency in a particular pool + /// Estimate the worth of an outgoing currency amount in the incoming /// currency. - fn foreign_to_pool( - currency_foreign: Self::Currency, - amount_foreign: Self::Balance, - currency_pool: Self::Currency, - ) -> Result; - - /// Estimate the worth of a pool currency in a particular foreign currency. - fn pool_to_foreign( - currency_pool: Self::Currency, - amount_pool: Self::Balance, - currency_foreign: Self::Currency, + fn stable_to_stable( + currency_out: Self::Currency, + amount_out: Self::Balance, + currency_in: Self::Currency, ) -> Result; } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index d8a61e4dd3..5b5e423369 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -226,7 +226,7 @@ impl ForeignInvestment for Pallet { } = T::Investment::collect_investment(who.clone(), investment_id)?; let amount_currency_payout = - T::CurrencyConverter::pool_to_foreign(pool_currency, amount_payment, return_currency)?; + T::CurrencyConverter::stable_to_stable(pool_currency, amount_payment, return_currency)?; Ok(ExecutedForeignCollectInvest { amount_currency_payout, diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index e4b0d0805e..84d40d0b3f 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -494,7 +494,9 @@ pub mod foreign_investments { use frame_support::pallet_prelude::PhantomData; use sp_runtime::{traits::Get, DispatchError}; - /// Simple stable coin amount converter from one stable to another. + /// Simple stable coin amount converter from one stable to another. Provides + /// a synchronous estimation of the amount of one stable currency in + /// another, e.g., the worth of 100 EthWrappedDai in USDC. /// /// For now, converts any `ForeignAsset` into another with the configured /// rate. @@ -513,42 +515,18 @@ pub mod foreign_investments { type Currency = CurrencyId; type Error = DispatchError; - fn foreign_to_pool( - currency_foreign: Self::Currency, - amount_foreign: Self::Balance, - currency_pool: Self::Currency, + fn stable_to_stable( + currency_out: Self::Currency, + amount_out: Self::Balance, + currency_in: Self::Currency, ) -> Result { - match (currency_foreign, currency_pool) { - (out, inc) if out == inc => Ok(amount_foreign), + match (currency_out, currency_in) { + (out, inc) if out == inc => Ok(amount_out), // TODO(future): Conversion must be limited to asset ids which reflect stable coins (CurrencyId::ForeignAsset(_out_id), CurrencyId::ForeignAsset(_in_id)) => { // NOTE: Rounding down to favor system side RateForeignToPool::get() - .checked_mul_int_floor(amount_foreign) - .ok_or(DispatchError::Arithmetic( - sp_arithmetic::ArithmeticError::Overflow, - )) - } - _ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)), - } - } - - fn pool_to_foreign( - currency_foreign: Self::Currency, - amount_foreign: Self::Balance, - currency_pool: Self::Currency, - ) -> Result { - match (currency_foreign, currency_pool) { - (out, inc) if out == inc => Ok(amount_foreign), - // TODO(future): Conversion must be limited to asset ids which reflect stable coins - (CurrencyId::ForeignAsset(_out_id), CurrencyId::ForeignAsset(_in_id)) => { - // NOTE: Rounding down to favor system side - RateForeignToPool::get() - .reciprocal_floor() - .ok_or(DispatchError::Arithmetic( - sp_arithmetic::ArithmeticError::DivisionByZero, - ))? - .checked_mul_int_floor(amount_foreign) + .checked_mul_int_floor(amount_out) .ok_or(DispatchError::Arithmetic( sp_arithmetic::ArithmeticError::Overflow, )) From 04748a9ded766af20ea916c67532f75093781c4f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Sun, 20 Aug 2023 10:02:38 +0200 Subject: [PATCH 42/96] docs: add errors --- pallets/foreign-investments/src/errors.rs | 13 ++++++++++++- pallets/foreign-investments/src/lib.rs | 17 ++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index 6f812d9a67..e23cc9aa68 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -17,18 +17,29 @@ use scale_info::TypeInfo; #[derive(Encode, Decode, TypeInfo, PalletError)] pub enum InvestError { + /// Failed to increase the investment. Increase, + /// Failed to decrease the unprocessed investment. Decrease, + /// Failed to transition after fulfilled swap order. FulfillSwapOrder, + /// Failed to transition a (partially) processed investment after an epoch + /// was executed. EpochExecution, } #[derive(Encode, Decode, TypeInfo, PalletError)] pub enum RedeemError { + /// Failed to increase the redemption. Increase, + /// Failed to collect the redemption. Collect, + /// Failed to decrease the unprocessed redemption. Decrease, - EpochExecution, + /// Failed to transition after fulfilled swap order. FulfillSwapOrder, + /// Failed to transition a (partially) processed redemption after an epoch + /// was executed. + EpochExecution, } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index cf28a37bf3..bb4df0bd5f 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -305,29 +305,16 @@ pub mod pallet { #[pallet::error] // TODO: Add more errors pub enum Error { - // TODO: Not used at the moment - /// Failed to retrieve the `RedemptionInfo` from the given - /// `TokenSwapOrderId`. - /// - /// NOTE: We must ensure, this can practically never happen! - RedemptionInfoNotFound, - // TODO: Not used at the moment - /// Failed to determine whether the corresponding currency can be either - /// used for payment or payout of an investment. - /// - /// NOTE: We must ensure, this can practically never happen! InvalidInvestmentCurrency, /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. - /// - /// NOTE: We must ensure, this can practically never happen! InvestmentInfoNotFound, /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. - /// - /// NOTE: We must ensure, this can practically never happen! TokenSwapReasonNotFound, + /// Failed to transition the `InvestState`. InvestError(InvestError), + /// Failed to transition the `RedeemState.` RedeemError(RedeemError), } From 92c2b2f28ec07d4483d604fb258a5d782a5bfbf0 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 21 Aug 2023 10:32:26 +0200 Subject: [PATCH 43/96] tests: fix decrease_invest same currencies --- libs/types/src/investments.rs | 9 +- .../foreign-investments/src/impls/invest.rs | 14 ++- pallets/foreign-investments/src/impls/mod.rs | 35 ++++-- .../foreign-investments/src/impls/redeem.rs | 15 ++- pallets/foreign-investments/src/types.rs | 21 ++-- pallets/liquidity-pools/src/inbound.rs | 2 +- pallets/pool-system/src/tests/mod.rs | 2 +- .../development/tests/liquidity_pools.rs | 118 ++++++++++++------ 8 files changed, 141 insertions(+), 75 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index c56fbb9095..5f38938d52 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -13,7 +13,7 @@ use cfg_primitives::OrderId; use cfg_traits::investments::InvestmentProperties; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::RuntimeDebug; +use frame_support::{dispatch::fmt::Debug, RuntimeDebug}; use scale_info::TypeInfo; use sp_arithmetic::traits::{EnsureAdd, EnsureSub}; use sp_runtime::{traits::Zero, DispatchError, DispatchResult}; @@ -177,7 +177,10 @@ pub struct ForeignInvestmentInfo { TypeInfo, MaxEncodedLen, )] -pub struct Swap { +pub struct Swap< + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + PartialEq, +> { /// The incoming currency, i.e. the desired one. pub currency_in: Currency, /// The outgoing currency, i.e. the one which should be replaced. @@ -186,7 +189,7 @@ pub struct Swap +impl Swap { /// Ensures that the ingoing and outgoing currencies of two swaps... diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 4f51fb9a8f..f16ea6de94 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -14,6 +14,7 @@ use core::cmp::Ordering; use cfg_types::investments::Swap; +use frame_support::dispatch::fmt::Debug; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, ArithmeticError, DispatchError, @@ -23,8 +24,8 @@ use crate::types::{InvestState, InvestTransition}; impl InvestState where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, { /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. @@ -90,8 +91,8 @@ where // Actual impl of transition impl InvestState where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// invest state diagram: @@ -846,6 +847,11 @@ where &self, swap: Swap, ) -> Result { + #[cfg(feature = "std")] + { + println!("Inside invest handle_decrease_non_foreign"); + dbg!(self, swap); + } if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 5b5e423369..237eb1b619 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -39,10 +39,8 @@ use crate::{ mod invest; mod redeem; -// Handles the second stage of updating investments. Whichever (potentially -// async) code path of the first stage concludes it (partially) should call -// `Swap::Config::SwapNotificationHandler::notify_status_update(swap_order_id, -// swapped_amount)`. +// Hook execution for (partially) fulfilled token swaps which should be consumed +// by `TokenSwaps`. impl StatusNotificationHook for Pallet { type Error = DispatchError; type Id = T::TokenSwapOrderId; @@ -314,9 +312,9 @@ impl Pallet { /// The following execution order must not be changed: /// /// 1. If the `InvestState` includes `SwapIntoReturnDone` without - /// `ActiveSwapIntoReturnCurrency`: Send executed decrease hook & transition - /// state into its form without `SwapIntoReturnDone`. If the state is just - /// `SwapIntoReturnDone`, kill it. + /// `ActiveSwapIntoReturnCurrency`: Prepare "executed decrease" hook & + /// transition state into its form without `SwapIntoReturnDone`. If the + /// state is just `SwapIntoReturnDone`, kill it. /// /// 2. Update the `InvestmentState` storage. This step is required as the /// next step reads this storage entry. @@ -339,6 +337,8 @@ impl Pallet { /// 6. Update the investment. This also includes setting it to zero. We /// assume the impl of `::Investment` handles this case. /// + /// 7. If "executed decrease" happened, send notification. + /// /// NOTES: /// * Must be called after transitioning any `InvestState` via /// `transition` to update the chain storage. @@ -350,7 +350,10 @@ impl Pallet { investment_id: T::InvestmentId, state: InvestState, ) -> DispatchResult { + // Must not send executed decrease notification before updating redemption + let mut maybe_executed_decrease: Option<(T::CurrencyId, T::Balance)> = None; // Do first round of updates and forward state, swap as well as invest amount + match state { InvestState::NoState => { InvestmentState::::remove(who, investment_id); @@ -377,7 +380,7 @@ impl Pallet { Ok((state, Some(swap), invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; + maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; InvestmentState::::insert(who, investment_id, new_state); @@ -385,7 +388,7 @@ impl Pallet { Ok((new_state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_amount, swap.currency_out)?; + maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; InvestmentState::::insert(who, investment_id, new_state); @@ -393,14 +396,14 @@ impl Pallet { Ok((new_state, Some(swap), invest_amount)) }, InvestState::SwapIntoReturnDone { done_swap } => { - Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount, done_swap.currency_in)?; + maybe_executed_decrease = Some((done_swap.currency_in, done_swap.amount)); InvestmentState::::remove(who, investment_id); Ok((InvestState::NoState, None, Zero::zero())) }, InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { - Self::notify_executed_decrease_invest(who, investment_id, done_swap.amount, done_swap.currency_in)?; + maybe_executed_decrease = Some((done_swap.currency_in, done_swap.amount)); let new_state = InvestState::InvestmentOngoing { invest_amount }; InvestmentState::::insert(who, investment_id, new_state); @@ -419,9 +422,15 @@ impl Pallet { } Self::deposit_redemption_event(who, investment_id, maybe_new_redeem_state); - // Finally, update investment after all states have been updated + // Update investment after all states have been updated T::Investment::update_investment(who, investment_id, invest_amount)?; + // Send notification after updating invest as else funds are still locked in investment account + if let Some((return_currency, decreased_amount)) = maybe_executed_decrease { + Self::notify_executed_decrease_invest(who, investment_id, return_currency, decreased_amount)?; + } + + Ok(()) }) .map_err(|e: DispatchError| e)? @@ -998,8 +1007,8 @@ impl Pallet { fn notify_executed_decrease_invest( who: &T::AccountId, investment_id: T::InvestmentId, - amount_decreased: T::Balance, return_currency: T::CurrencyId, + amount_decreased: T::Balance, ) -> DispatchResult { T::ExecutedDecreaseInvestHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 5bd83b80da..69d25f9379 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -12,7 +12,7 @@ // GNU General Public License for more details. use cfg_types::investments::Swap; -use frame_support::ensure; +use frame_support::{dispatch::fmt::Debug, ensure}; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, ArithmeticError, DispatchError, @@ -38,8 +38,8 @@ use crate::types::{ impl RedeemState where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, { /// Solely apply state machine to transition one `RedeemState` into another /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#Redemption-States @@ -176,8 +176,8 @@ where impl InnerRedeemState where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, { /// Returns the potentially existing active swap into return currency: /// * If the state includes `ActiveSwapIntoReturnCurrency`, it returns the @@ -420,7 +420,6 @@ where RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap }), RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), // Throw for states without `Redeeming` - // TODO: Create pallet error NotRedeeming _ => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), } } @@ -787,8 +786,8 @@ where // Actual impl of transition impl RedeemState where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// redeem state diagram: diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 856e5eafc4..479047fb50 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -13,6 +13,7 @@ use cfg_types::investments::Swap; use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::dispatch::fmt::Debug; use scale_info::TypeInfo; use sp_runtime::traits::{EnsureAdd, EnsureSub}; @@ -45,8 +46,8 @@ pub enum TokenSwapReason { MaxEncodedLen, )] pub enum InvestState< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, > { #[default] /// Placeholder state for initialization which will never be stored on @@ -142,8 +143,8 @@ pub enum InvestState< /// updating an unprocessed investment. #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum InvestTransition< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, > { /// Assumes `swap.currency_in` is pool currency as we increase here. IncreaseInvestOrder(Swap), @@ -179,8 +180,8 @@ pub enum InvestTransition< MaxEncodedLen, )] pub enum RedeemState< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, > { #[default] /// Placeholder state for initialization which will never be stored on @@ -208,8 +209,8 @@ pub enum RedeemState< Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] pub enum InnerRedeemState< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, > { /// The redemption is pending until it is processed during epoch execution. Redeeming { redeem_amount: Balance }, @@ -318,8 +319,8 @@ pub enum InnerRedeemState< /// updating an unprocessed redemption. #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RedeemTransition< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord, - Currency: Clone + Copy + PartialEq, + Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + Currency: Clone + Copy + PartialEq + Debug, > { IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index baf69579bb..7a4358fb8a 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -155,7 +155,7 @@ where /// Cancels an invest order by decreasing by the entire unprocessed /// investment amount. /// - /// On success, a swap back into the provided return currency initiated. + /// On success, initiates a swap back into the provided return currency. /// /// The finalization of this call (fulfillment of the swap) is assumed to be /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` diff --git a/pallets/pool-system/src/tests/mod.rs b/pallets/pool-system/src/tests/mod.rs index 4749994567..29ebdd03e3 100644 --- a/pallets/pool-system/src/tests/mod.rs +++ b/pallets/pool-system/src/tests/mod.rs @@ -10,7 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::{PoolMutate, investments::TrancheCurrency as TrancheCurrencyT, TrancheTokenPrice}; +use cfg_traits::{investments::TrancheCurrency as TrancheCurrencyT, PoolMutate, TrancheTokenPrice}; use cfg_types::{ epoch::EpochState, fixed_point::Rate, diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 7eaf5bf314..5089eedefe 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -86,7 +86,8 @@ use crate::{ setup::{cfg, dollar, ALICE, BOB, PARA_ID_MOONBEAM}, test_net::{Development, Moonbeam, RelayChain, TestNet}, tests::liquidity_pools::utils::{ - get_default_moonbeam_native_token_location, DEFAULT_MOONBEAM_LOCATION, + get_default_moonbeam_native_token_location, liquidity_pools_transferable_multilocation, + DEFAULT_MOONBEAM_LOCATION, }, }, utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, @@ -1183,7 +1184,7 @@ fn inbound_increase_invest_order() { } #[test] -fn inbound_decrease_invest_order() { +fn inbound_decrease_invest_order_same_currencies() { TestNet::reset(); Development::execute_with(|| { @@ -1217,6 +1218,21 @@ fn inbound_decrease_invest_order() { amount: decrease_amount, }; + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + utils::enable_liquidity_pool_transferability( + currency_id, + Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))), + ); + // Execute byte message assert_ok!(LiquidityPools::submit( utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, @@ -1231,12 +1247,9 @@ fn inbound_decrease_invest_order() { ), final_amount ); - // The transfer does not happen right away, so should still be in investor's - // wallet - assert_eq!( - OrmlTokens::free_balance(currency_id, &investor), - decrease_amount - ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::InvestOrderUpdated { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), @@ -1245,6 +1258,13 @@ fn inbound_decrease_invest_order() { amount: final_amount } .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); assert_eq!( pallet_investments::Pallet::::acc_active_invest_order( investment_id(pool_id, default_tranche_id(pool_id)) @@ -1646,9 +1666,11 @@ mod utils { use liquidity_pools_gateway_routers::{ ethereum_xcm::EthereumXCMRouter, DomainRouter, XCMRouter, XcmTransactInfo, }; + use orml_asset_registry::Metadata; use super::*; use crate::{ + chain::centrifuge::development, liquidity_pools::pallet::development::tests::register_ausd, utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, }; @@ -1675,33 +1697,6 @@ mod utils { } } - /// Returns a `VersionedMultiLocation` that can be converted into - /// `LiquidityPoolsWrappedToken` which is required for cross chain asset - /// registration and transfer. - pub fn liquidity_pools_transferable_multilocation( - chain_id: u64, - address: [u8; 20], - ) -> VersionedMultiLocation { - VersionedMultiLocation::V3(MultiLocation { - parents: 0, - interior: - X3( - PalletInstance( - ::PalletInfo::index::< - LiquidityPools, - >() - .expect("LiquidityPools should have pallet index") - .saturated_into(), - ), - GlobalConsensus(NetworkId::Ethereum { chain_id }), - AccountKey20 { - network: None, - key: address, - }, - ), - }) - } - pub fn set_test_domain_router( evm_chain_id: u64, xcm_domain_location: VersionedMultiLocation, @@ -1837,6 +1832,59 @@ mod utils { )); } + /// Returns a `VersionedMultiLocation` that can be converted into + /// `LiquidityPoolsWrappedToken` which is required for cross chain asset + /// registration and transfer. + pub fn liquidity_pools_transferable_multilocation( + chain_id: u64, + address: [u8; 20], + ) -> VersionedMultiLocation { + VersionedMultiLocation::V3(MultiLocation { + parents: 0, + interior: + X3( + PalletInstance( + ::PalletInfo::index::< + LiquidityPools, + >() + .expect("LiquidityPools should have pallet index") + .saturated_into(), + ), + GlobalConsensus(NetworkId::Ethereum { chain_id }), + AccountKey20 { + network: None, + key: address, + }, + ), + }) + } + + /// Enables `LiquidityPoolsTransferable` in the custom asset metadata for + /// the given currency_id. If provided, also updates the location which is + /// required for LiquidityPoolsWrappedToken conversions. + pub fn enable_liquidity_pool_transferability( + currency_id: CurrencyId, + maybe_location: Option>, + ) { + let metadata = Metadata::::get(currency_id) + .expect("Currency should be registered"); + + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + maybe_location, + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + ..metadata.additional + }) + )); + } + /// Returns metadata for the given data with existential deposit of /// 1_000_000. pub fn asset_metadata( From 50ee08cd679e258e2ffe76556107afaaa3ef6108 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 21 Aug 2023 10:44:35 +0200 Subject: [PATCH 44/96] Delete swap_delta.md --- swap_delta.md | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 swap_delta.md diff --git a/swap_delta.md b/swap_delta.md deleted file mode 100644 index 8af0f0ba49..0000000000 --- a/swap_delta.md +++ /dev/null @@ -1,26 +0,0 @@ -```plantuml -@startuml -skinparam maxMessageSize 100 - -state Redemption_Swap as "Redemption: \nActiveSwapIntoReturnCurrency \n(& SwapIntoReturnDone) \n(& Collectable) \n(&Redeeming) \n(&Invested)" #CAFFBF { - state SwapR__Invest_SwapPool as "&\n\n Investment: \nActiveSwapIntoPool \n(& Investing)" #CAFFBF - state SwapR__Invest_SwapReturn as "&\n\n Investment: \nActiveSwapIntoReturn \n(& SwapIntoReturnDone) \n(&Investing)" #CAFFBF -} - -state Redemption_Swap_DoneReturn as "Redemption: \nActiveSwapIntoReturnCurrency \n& SwapIntoReturnDone \n(& Collectable) \n(&Redeeming) \n(&Invested)" { - state SwapR__Invest_DonePool as "&\n\n Investment: \nSwapIntoPoolDone \n(&Investing)" -} - -state RedemptionNoSwap as "Redemption: \nSwapIntoReturnDone \n(& Collectable) \n(&Redeeming) \n(&Invested)" { - state NoSwapR__Invest_SwapPool_DonePool as "&\n\n Investment: \nActiveSwapIntoPool \n& SwapIntoPoolDone \n(& Investing)" - state NoSwapR__Invest_DonePool as "&\n\n Investment: \nSwapIntoPoolDone \n(&Investing)" -} - -SwapR__Invest_SwapPool ----> NoSwapR__Invest_SwapPool_DonePool : pool_swap > return_swap \n\n(all attributes in () kept) -SwapR__Invest_SwapPool ----> NoSwapR__Invest_DonePool : pool_swap == return_swap \n\n(all attributes in () kept) -SwapR__Invest_SwapPool ----> SwapR__Invest_DonePool : pool_swap < return_swap \n\n(all attributes in () kept) - -SwapR__Invest_SwapReturn --> SwapR__Invest_SwapReturn : any amount \n\n(all attributes in () kept) - -@enduml -``` \ No newline at end of file From f226e64f343035352ef084978772b0ff7e6ce122 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 21 Aug 2023 14:10:12 +0200 Subject: [PATCH 45/96] refactor: return currency -> foreign currency --- libs/traits/src/investments.rs | 22 +- libs/types/src/investments.rs | 8 +- .../foreign-investments/src/impls/invest.rs | 392 +++++++++--------- pallets/foreign-investments/src/impls/mod.rs | 158 +++---- .../foreign-investments/src/impls/redeem.rs | 298 ++++++------- pallets/foreign-investments/src/types.rs | 111 ++--- pallets/liquidity-pools/src/hooks.rs | 6 +- pallets/liquidity-pools/src/inbound.rs | 10 +- 8 files changed, 507 insertions(+), 498 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 4da4de539b..049ead7718 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -286,10 +286,10 @@ pub trait ForeignInvestment { type CollectInvestResult; /// Initiates the increment of a foreign investment amount in - /// `return_currency` of who into the investment class `pool_currency` to + /// `foreign_currency` of who into the investment class `pool_currency` to /// amount. /// - /// NOTE: In general, we can assume that the return and pool currencies + /// NOTE: In general, we can assume that the foreign and pool currencies /// mismatch and that swapping one into the other happens asynchronously. In /// that case, the finalization of updating the investment needs to be /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. @@ -297,15 +297,15 @@ pub trait ForeignInvestment { who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, - return_currency: Self::CurrencyId, + foreign_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; /// Initiates the decrement of a foreign investment amount in - /// `return_currency` of who into the investment class `pool_currency` to + /// `foreign_currency` of who into the investment class `pool_currency` to /// amount. /// - /// NOTE: In general, we can assume that the return and pool currencies + /// NOTE: In general, we can assume that the foreign and pool currencies /// mismatch and that swapping one into the other happens asynchronously. In /// that case, the finalization of updating the investment needs to be /// handled decoupled from the ForeignInvestment trait, e.g., by some hook. @@ -313,12 +313,12 @@ pub trait ForeignInvestment { who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, - return_currency: Self::CurrencyId, + foreign_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; /// Initiates the increment of a foreign redemption amount from - /// `pool_currency` of who into `return_currency` to amount. + /// `pool_currency` of who into `foreign_currency` to amount. /// /// NOTE: The incrementing redemption amount is bound by the processed /// investment amount. @@ -329,7 +329,7 @@ pub trait ForeignInvestment { ) -> Result<(), Self::Error>; /// Initiates the decrement of a foreign redemption amount from - /// `pool_currency` of who into `return_currency` to amount. + /// `pool_currency` of who into `foreign_currency` to amount. /// /// NOTE: The decrementing redemption amount is bound by the previously /// incremented redemption amount. @@ -345,7 +345,7 @@ pub trait ForeignInvestment { fn collect_foreign_investment( who: &AccountId, investment_id: Self::InvestmentId, - return_currency: Self::CurrencyId, + foreign_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result; @@ -354,11 +354,11 @@ pub trait ForeignInvestment { /// appended to the next active order for this investment. /// /// NOTE: The currency of the collected amount will be `pool_currency` - /// whereas the user eventually wants to receive it in `return_currency`. + /// whereas the user eventually wants to receive it in `foreign_currency`. fn collect_foreign_redemption( who: &AccountId, investment_id: Self::InvestmentId, - return_currency: Self::CurrencyId, + foreign_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 5f38938d52..c9ffb4cac6 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -194,9 +194,9 @@ impl { /// The currency in which `DecreaseInvestOrder` was realised - pub return_currency: Currency, + pub foreign_currency: Currency, /// The amount of `currency` that was actually executed in the original /// `DecreaseInvestOrder` message, i.e., the amount by which the /// investment order was actually decreased by. @@ -247,7 +247,7 @@ pub struct ExecutedForeignCollectInvest { #[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ExecutedForeignCollectRedeem { - /// The return currency in which the payout takes place + /// The foreign currency in which the payout takes place pub currency: Currency, /// The amount of `currency` being paid out to the investor pub amount_currency_payout: Balance, diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index f16ea6de94..90e9686ef9 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -58,19 +58,19 @@ where InvestState::NoState => None, InvestState::InvestmentOngoing { .. } => None, InvestState::ActiveSwapIntoPoolCurrency { swap } => Some(swap), - InvestState::ActiveSwapIntoReturnCurrency { swap } => Some(swap), + InvestState::ActiveSwapIntoForeignCurrency { swap } => Some(swap), InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, .. } => { + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { Some(swap) }, - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, .. } => { + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { Some(swap) }, - InvestState::SwapIntoReturnDone { .. } => None, - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { .. } => None, + InvestState::SwapIntoForeignDone { .. } => None, + InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => None, } } @@ -79,10 +79,10 @@ where match *self { InvestState::InvestmentOngoing { invest_amount} | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } | - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { invest_amount, .. } | + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | + InvestState::SwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, _ => Balance::zero() } } @@ -96,7 +96,7 @@ where { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// invest state diagram: - /// * If there is no swap into return currency, the pool currency swap + /// * If there is no swap into foreign currency, the pool currency swap /// amount is increased. /// * Else, resolves opposite swap directions by immediately fulfilling the /// side with lower amounts; or both if the swap amounts are equal. @@ -104,34 +104,35 @@ where /// When we increase an investment, we normally have to swap it into pool /// currency (`ActiveSwapIntoPoolCurrency`) before it can be invested /// (`ActiveInvestmentOngoing`). However, if the current state includes - /// swapping back into pool currency (`ActiveSwapIntoReturnCurrency`) as the - /// result of a previous decrement, then we can minimize the amount which - /// needs to be swapped such that we always have **at most a single active - /// swap** which is the maximum of `pool_swap.amount` and - /// `return_swap.amount`. When we do this, we always need to bump the - /// investment amount as well as the `SwapIntoReturnDone` amount as a result - /// of immediately fulfilling the pool swap order up to the possible amount. + /// swapping back into pool currency (`ActiveSwapIntoForeignCurrency`) as + /// the result of a previous decrement, then we can minimize the amount + /// which needs to be swapped such that we always have **at most a single + /// active swap** which is the maximum of `pool_swap.amount` and + /// `foreign_swap.amount`. When we do this, we always need to bump the + /// investment amount as well as the `SwapIntoForeignDone` amount as a + /// result of immediately fulfilling the pool swap order up to the possible + /// amount. /// /// Example: - /// * Say before my pre invest state has `return_done = 1000` and - /// `return_swap.amount = 500`. Now we look at three scenarios in which we - /// increase below, exactly at and above the `return_swap.amount`: - /// * a) If we increase by 500, we can reduce the `return_swap.amount` - /// fully, which we denote by adding the 500 to the `return_done` amount. + /// * Say before my pre invest state has `foreign_done = 1000` and + /// `foreign_swap.amount = 500`. Now we look at three scenarios in which we + /// increase below, exactly at and above the `foreign_swap.amount`: + /// * a) If we increase by 500, we can reduce the `foreign_swap.amount` + /// fully, which we denote by adding the 500 to the `foreign_done` amount. /// Moreover, we can immediately invest the 500. The resulting state is /// `(done_amount = 1500, investing = 500)`. - /// * b) If we increase by 400, we can reduce the `return_swap.amount` only - /// by 400 and increase both the `investing` as well as `return_done` + /// * b) If we increase by 400, we can reduce the `foreign_swap.amount` only + /// by 400 and increase both the `investing` as well as `foreign_done` /// amount by that. The resulting state is - /// `(done_amount = 1400, return_swap.amount = 100, investing = 400)`. - /// * c) If we increase by 600, we can reduce the `return_swap.amount` fully - /// and need to add a swap into pool currency for 100. Moreover both the - /// `investing` as well as `return_done` amount can only be increased by - /// 500. The resulting state is + /// `(done_amount = 1400, foreign_swap.amount = 100, investing = 400)`. + /// * c) If we increase by 600, we can reduce the `foreign_swap.amount` + /// fully and need to add a swap into pool currency for 100. Moreover both + /// the `investing` as well as `foreign_done` amount can only be increased + /// by 500. The resulting state is /// `(done_amount = 1500, pool_swap.amount = 100, investing = 500)`. /// /// NOTE: We can ignore handling all states which include - /// `*SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency*` as we + /// `*SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency*` as we /// consume the done amount and transition in the post transition phase. /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure @@ -160,22 +161,22 @@ where }, }) } - // Reduce return swap amount by the increasing amount and increase investing amount as - // well adding return_done amount by the minimum of active swap amounts - Self::ActiveSwapIntoReturnCurrency { swap: return_swap } => { - swap.ensure_currencies_match(return_swap, false)?; - let invest_amount = swap.amount.min(return_swap.amount); - let done_amount = swap.amount.min(return_swap.amount); - - match swap.amount.cmp(&return_swap.amount) { + // Reduce foreign swap amount by the increasing amount and increase investing amount as + // well adding foreign_done amount by the minimum of active swap amounts + Self::ActiveSwapIntoForeignCurrency { swap: foreign_swap } => { + swap.ensure_currencies_match(foreign_swap, false)?; + let invest_amount = swap.amount.min(foreign_swap.amount); + let done_amount = swap.amount.min(foreign_swap.amount); + + match swap.amount.cmp(&foreign_swap.amount) { // pool swap amount is immediately invested and done amount increased equally Ordering::Equal => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + // safe since swap.amount < foreign_swap.amount + amount: foreign_swap.amount - swap.amount, + ..*foreign_swap }, done_amount, invest_amount, @@ -183,17 +184,17 @@ where ) } // swap amount is immediately invested and done amount increased equally - Ordering::Less => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - done_swap: *return_swap, + Ordering::Less => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap: *foreign_swap, invest_amount, }), - // return swap amount is immediately invested and done amount increased equally + // foreign swap amount is immediately invested and done amount increased equally Ordering::Greater => { Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, + // safe since swap.amount > foreign_swap.amount + amount: swap.amount - foreign_swap.amount, ..swap }, done_amount, @@ -218,26 +219,26 @@ where invest_amount: *invest_amount, }) } - // Reduce return swap amount by the increasing amount and increase investing amount as - // well adding return_done amount by the minimum of active swap amounts - Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap: return_swap, + // Reduce foreign swap amount by the increasing amount and increase investing amount as + // well adding foreign_done amount by the minimum of active swap amounts + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: foreign_swap, invest_amount, } => { - swap.ensure_currencies_match(return_swap, false)?; + swap.ensure_currencies_match(foreign_swap, false)?; let invest_amount = - invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; - let done_amount = swap.amount.min(return_swap.amount); + invest_amount.ensure_add(swap.amount.min(foreign_swap.amount))?; + let done_amount = swap.amount.min(foreign_swap.amount); - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { // pool swap amount is immediately invested and done amount increased equally Ordering::Equal => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + // safe since swap.amount < foreign_swap.amount + amount: foreign_swap.amount - swap.amount, + ..*foreign_swap }, done_amount, invest_amount, @@ -245,17 +246,17 @@ where ) } // swap amount is immediately invested and done amount increased equally - Ordering::Less => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { - done_swap: *return_swap, + Ordering::Less => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap: *foreign_swap, invest_amount, }), - // return swap amount is immediately invested and done amount increased equally + // foreign swap amount is immediately invested and done amount increased equally Ordering::Greater => { Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, + // safe since swap.amount > foreign_swap.amount + amount: swap.amount - foreign_swap.amount, ..swap }, done_amount, @@ -265,46 +266,46 @@ where } } } - // Reduce amount of return by the increasing amount and increase investing as well as - // return_done amount by the minimum of active swap amounts - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: return_swap, + // Reduce amount of foreign by the increasing amount and increase investing as well as + // foreign_done amount by the minimum of active swap amounts + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: foreign_swap, done_amount, } => { - swap.ensure_currencies_match(return_swap, false)?; - let invest_amount = swap.amount.min(return_swap.amount); + swap.ensure_currencies_match(foreign_swap, false)?; + let invest_amount = swap.amount.min(foreign_swap.amount); let done_amount = invest_amount.ensure_add(*done_amount)?; // pool swap amount is immediately invested and done amount increased equally - match swap.amount.cmp(&return_swap.amount) { - Ordering::Equal => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + match swap.amount.cmp(&foreign_swap.amount) { + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, - ..*return_swap + ..*foreign_swap }, invest_amount, }), // swap amount is immediately invested and done amount increased equally Ordering::Less => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + // safe since swap.amount < foreign_swap.amount + amount: foreign_swap.amount - swap.amount, + ..*foreign_swap }, done_amount, invest_amount, }, ) } - // return swap amount is immediately invested and done amount increased equally + // foreign swap amount is immediately invested and done amount increased equally Ordering::Greater => { Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, + // safe since swap.amount > foreign_swap.amount + amount: swap.amount - foreign_swap.amount, ..swap }, done_amount, @@ -314,48 +315,48 @@ where } } } - // Reduce amount of return swap by increasing amount and increase investing as well as - // return_done amount by minimum of swap amounts - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: return_swap, + // Reduce amount of foreign swap by increasing amount and increase investing as well as + // foreign_done amount by minimum of swap amounts + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: foreign_swap, done_amount, invest_amount, } => { - swap.ensure_currencies_match(return_swap, false)?; + swap.ensure_currencies_match(foreign_swap, false)?; let invest_amount = - invest_amount.ensure_add(swap.amount.min(return_swap.amount))?; + invest_amount.ensure_add(swap.amount.min(foreign_swap.amount))?; let done_amount = swap .amount - .min(return_swap.amount) + .min(foreign_swap.amount) .ensure_add(*done_amount)?; - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { // pool swap amount is immediately invested and done amount increased equally - Ordering::Equal => Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, - ..*return_swap + ..*foreign_swap }, invest_amount, }), // swap amount is immediately invested and done amount increased equally Ordering::Less => Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < return_swap.amount - amount: return_swap.amount - swap.amount, - ..*return_swap + // safe since swap.amount < foreign_swap.amount + amount: foreign_swap.amount - swap.amount, + ..*foreign_swap }, done_amount, invest_amount, }, ), - // return swap amount is immediately invested and done amount increased equally + // foreign swap amount is immediately invested and done amount increased equally Ordering::Greater => Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > return_swap.amount - amount: swap.amount - return_swap.amount, + // safe since swap.amount > foreign_swap.amount + amount: swap.amount - foreign_swap.amount, ..swap }, done_amount, @@ -373,7 +374,7 @@ where /// Handle `decrease` transitions depicted by `msg::decrease` edges in the /// state diagram: - /// * If there is no swap into pool currency, the return currency swap + /// * If there is no swap into pool currency, the foreign currency swap /// amount is increased up to the ongoing investment amount which is not /// yet processed. /// * Else, resolves opposite swap directions by immediately fulfilling the @@ -385,7 +386,7 @@ where /// at this stage! /// /// NOTE: We can ignore handling all states which include - /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we /// consume the done amount and transition in the post transition phase. /// Moreover, we can ignore handling all states which do not include /// `ActiveSwapIntoPoolCurrency` or `InvestmentOngoing` as we cannot reduce @@ -401,21 +402,21 @@ where match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency InvestState::NoState - | InvestState::ActiveSwapIntoReturnCurrency { .. } - | InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } => { + | InvestState::ActiveSwapIntoForeignCurrency { .. } + | InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { .. } => { Err(DispatchError::Other("Invalid invest state when transitioning a decrease")) }, - // Increment return swap amount up to ongoing investment + // Increment foreign swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { match swap.amount.cmp(invest_amount) { Ordering::Less => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, invest_amount: *invest_amount - swap.amount, }) }, Ordering::Equal => { - Ok(Self::ActiveSwapIntoReturnCurrency { swap }) + Ok(Self::ActiveSwapIntoForeignCurrency { swap }) } // should never occur but let's be safe here Ordering::Greater => { @@ -429,10 +430,10 @@ where match swap.amount.cmp(&pool_swap.amount) { Ordering::Equal => { - Ok(Self::SwapIntoReturnDone { done_swap: swap }) + Ok(Self::SwapIntoForeignDone { done_swap: swap }) }, Ordering::Less => { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap: Swap { // safe because swap.amount < pool_swap.amount amount: pool_swap.amount - swap.amount, @@ -447,7 +448,7 @@ where } } }, - // Increment `return_done` up to pool swap amount and increment return swap amount up to ongoing investment + // Increment `foreign_done` up to pool swap amount and increment foreign swap amount up to ongoing investment InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount, @@ -459,7 +460,7 @@ where if swap.amount < pool_swap.amount { Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { // safe because done_amount is min amount: pool_swap.amount - done_amount, @@ -470,13 +471,13 @@ where }, ) } else if swap.amount == pool_swap.amount { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount, }) } else if swap.amount < max_decrease_amount { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { // safe because done_amount is min amount: swap.amount - done_amount, @@ -487,7 +488,7 @@ where }, ) } else if swap.amount == max_decrease_amount { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { // safe because done_amount is min amount: swap.amount - done_amount, @@ -501,24 +502,24 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } }, - // Increment return swap up to ongoing investment - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap: return_swap, + // Increment foreign swap up to ongoing investment + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: foreign_swap, invest_amount, } => { - swap.ensure_currencies_match(return_swap, true)?; - let amount = return_swap.amount.ensure_add(swap.amount)?; + swap.ensure_currencies_match(foreign_swap, true)?; + let amount = foreign_swap.amount.ensure_add(swap.amount)?; match swap.amount.cmp(invest_amount) { Ordering::Less => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: Swap { amount, ..swap }, // safe because invest_amount > swap_amount invest_amount: *invest_amount - swap.amount, }) }, Ordering::Equal => { - Ok(Self::ActiveSwapIntoReturnCurrency { + Ok(Self::ActiveSwapIntoForeignCurrency { swap: Swap { amount, ..swap }, }) }, @@ -528,18 +529,18 @@ where }, } }, - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: return_swap, + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: foreign_swap, done_amount, invest_amount, } => { - swap.ensure_currencies_match(return_swap, true)?; - let amount = return_swap.amount.ensure_add(swap.amount)?; + swap.ensure_currencies_match(foreign_swap, true)?; + let amount = foreign_swap.amount.ensure_add(swap.amount)?; match swap.amount.cmp(invest_amount) { Ordering::Less => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { amount, ..swap }, done_amount: *done_amount, // safe because swap.amount < invest_amount @@ -548,7 +549,7 @@ where ) }, Ordering::Equal => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount, ..swap }, done_amount: *done_amount, }) @@ -570,17 +571,17 @@ where /// `order_partial` and `order_full` edges in the state diagram. /// /// Please note, that we ensure that there can always be at most one swap, - /// either into pool currency (`ActiveSwapIntoPoolCurrency`) or into return - /// currency (`ActiveSwapIntoReturnCurrency`). Thus, if the previous state + /// either into pool currency (`ActiveSwapIntoPoolCurrency`) or into foreign + /// currency (`ActiveSwapIntoForeignCurrency`). Thus, if the previous state /// (`&self`) is into pool, we know the incoming transition is made from /// return into pool currency and vice versa if the previous state is - /// swapping into return currency. + /// swapping into foreign currency. /// /// This transition should always increase the active ongoing /// investment. /// /// NOTE: We can ignore handling all states which include - /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we /// consume the done amount and transition in the post transition phase. /// Moreover, we can ignore handling all states which do not include /// `ActiveSwapInto{Pool, Return}Currency` as else there cannot be an active @@ -590,7 +591,7 @@ where /// this can never occur! // FIXME(@review): This handler assumes partial fulfillments and 1-to-1 - // conversion of amounts, i.e., 100 `return_currency` equals 100 + // conversion of amounts, i.e., 100 `foreign_currency` equals 100 // `pool_currency`. If we use the CurrencyConverter, the amounts could be off as // the `CurrencyConverter` is decoupled from the `TokenSwaps` trait. fn handle_fulfilled_swap_order( @@ -628,19 +629,19 @@ where } } }, - // Increment done_return by swapped amount - InvestState::ActiveSwapIntoReturnCurrency { swap: return_swap } => { - swap.ensure_currencies_match(return_swap, true)?; + // Increment done_foreign by swapped amount + InvestState::ActiveSwapIntoForeignCurrency { swap: foreign_swap } => { + swap.ensure_currencies_match(foreign_swap, true)?; - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { Ordering::Equal => { - Ok(Self::SwapIntoReturnDone { done_swap: swap }) + Ok(Self::SwapIntoForeignDone { done_swap: swap }) } Ordering::Less => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, + // safe because foreign_swap.amount > swap.amount + amount: foreign_swap.amount - swap.amount, ..swap }, done_amount: swap.amount, @@ -680,26 +681,26 @@ where } } }, - // Increment done_return by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { - swap: return_swap, + // Increment done_foreign by swapped amount, leave invest amount untouched + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: foreign_swap, invest_amount, } => { - swap.ensure_currencies_match(return_swap, true)?; + swap.ensure_currencies_match(foreign_swap, true)?; - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { Ordering::Equal => { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount: *invest_amount, }) } Ordering::Less => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, + // safe because foreign_swap.amount > swap.amount + amount: foreign_swap.amount - swap.amount, ..swap }, done_amount: swap.amount, @@ -713,17 +714,17 @@ where } } }, - // Increment done_return by swapped amount - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { - swap: return_swap, + // Increment done_foreign by swapped amount + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: foreign_swap, done_amount, } => { - swap.ensure_currencies_match(return_swap, true)?; + swap.ensure_currencies_match(foreign_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { Ordering::Equal => { - Ok(Self::SwapIntoReturnDone { + Ok(Self::SwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap @@ -731,10 +732,10 @@ where }) } Ordering::Less => { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, + // safe because foreign_swap.amount > swap.amount + amount: foreign_swap.amount - swap.amount, ..swap }, done_amount, @@ -746,18 +747,18 @@ where } } }, - // Increment done_return by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { - swap: return_swap, + // Increment done_foreign by swapped amount, leave invest amount untouched + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: foreign_swap, done_amount, invest_amount, } => { - swap.ensure_currencies_match(return_swap, true)?; + swap.ensure_currencies_match(foreign_swap, true)?; let done_amount = done_amount.ensure_add(swap.amount)?; - match swap.amount.cmp(&return_swap.amount) { + match swap.amount.cmp(&foreign_swap.amount) { Ordering::Equal => { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, ..swap @@ -767,10 +768,10 @@ where } Ordering::Less => { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because return_swap.amount > swap.amount - amount: return_swap.amount - swap.amount, + // safe because foreign_swap.amount > swap.amount + amount: foreign_swap.amount - swap.amount, ..swap }, done_amount, @@ -785,7 +786,7 @@ where } }, _ => Err(DispatchError::Other( - "Invalid invest state, should automatically be transitioned into state without AndSwapIntoReturnDone", + "Invalid invest state, should automatically be transitioned into state without AndSwapIntoForeignDone", )), } } @@ -794,7 +795,7 @@ where /// currencies. /// /// NOTE: We can ignore handling all states which include - /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we /// consume the done amount and transition in the post transition phase. /// Moreover, we can ignore any state which involves an active swap, i.e. /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the @@ -814,11 +815,11 @@ where invest_amount: invest_amount.ensure_add(swap.amount)?, }), Self::ActiveSwapIntoPoolCurrency { .. } - | Self::ActiveSwapIntoReturnCurrency { .. } + | Self::ActiveSwapIntoForeignCurrency { .. } | Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } - | Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { .. } - | Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { .. } - | Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + | Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { .. } + | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { .. } + | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { .. } => Err(DispatchError::Other( "Invalid invest state when transitioning an increased swap order with the same in- \ @@ -826,7 +827,7 @@ where )), _ => Err(DispatchError::Other( "Invalid invest state, should automatically be transitioned into state without \ - AndSwapIntoReturnDone", + AndSwapIntoForeignDone", )), } } @@ -835,7 +836,7 @@ where /// currencies. /// /// NOTE: We can ignore handling all states which include - /// `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` as we + /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we /// consume the done amount and transition in the post transition phase. /// Moreover, we can ignore any state which involves an active swap, i.e. /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the @@ -854,12 +855,12 @@ where } if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { - Ok(InvestState::SwapIntoReturnDoneAndInvestmentOngoing { + Ok(InvestState::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount: invest_amount.ensure_sub(swap.amount)?, }) } else { - Ok(Self::SwapIntoReturnDone { done_swap: swap }) + Ok(Self::SwapIntoForeignDone { done_swap: swap }) } } // should never occur but let's be safe here @@ -899,26 +900,31 @@ where }) } } - Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, .. } => { + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrency { swap }) + Ok(Self::ActiveSwapIntoForeignCurrency { swap }) } else { - Ok(Self::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, invest_amount: unprocessed_amount, }) } } - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount }) + Ok( + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + }, + ) } else { Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, invest_amount: unprocessed_amount, @@ -926,28 +932,28 @@ where ) } } - Self::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, .. } => { + Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::SwapIntoReturnDone { done_swap }) + Ok(Self::SwapIntoForeignDone { done_swap }) } else { - Ok(Self::SwapIntoReturnDoneAndInvestmentOngoing { + Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap, invest_amount: unprocessed_amount, }) } } - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, }) } else { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, invest_amount: unprocessed_amount, diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 237eb1b619..1fd82d8edb 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -94,7 +94,7 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, amount: T::Balance, - return_currency: T::CurrencyId, + foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); @@ -110,7 +110,7 @@ impl ForeignInvestment for Pallet { let post_state = pre_state .transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, - currency_out: return_currency, + currency_out: foreign_currency, amount, })) .map_err(|e| { @@ -128,7 +128,7 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, amount: T::Balance, - return_currency: T::CurrencyId, + foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); @@ -144,7 +144,7 @@ impl ForeignInvestment for Pallet { let post_state = pre_state .transition(InvestTransition::DecreaseInvestOrder(Swap { currency_in: pool_currency, - currency_out: return_currency, + currency_out: foreign_currency, amount, })) .map_err(|e| { @@ -213,7 +213,7 @@ impl ForeignInvestment for Pallet { fn collect_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, - return_currency: T::CurrencyId, + foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is @@ -223,8 +223,11 @@ impl ForeignInvestment for Pallet { amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; - let amount_currency_payout = - T::CurrencyConverter::stable_to_stable(pool_currency, amount_payment, return_currency)?; + let amount_currency_payout = T::CurrencyConverter::stable_to_stable( + pool_currency, + amount_payment, + foreign_currency, + )?; Ok(ExecutedForeignCollectInvest { amount_currency_payout, @@ -236,7 +239,7 @@ impl ForeignInvestment for Pallet { fn collect_foreign_redemption( who: &T::AccountId, investment_id: T::InvestmentId, - return_currency: T::CurrencyId, + foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; @@ -246,12 +249,12 @@ impl ForeignInvestment for Pallet { Ok::<(), DispatchError>(()) })?; - // Transition state to initiate swap from pool to return currency + // Transition state to initiate swap from pool to foreign currency let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); let post_state = pre_state .transition(RedeemTransition::Collect(SwapOf:: { amount: collected.amount_collected, - currency_in: return_currency, + currency_in: foreign_currency, currency_out: pool_currency, })) .map_err(|e| { @@ -311,10 +314,10 @@ impl Pallet { /// /// The following execution order must not be changed: /// - /// 1. If the `InvestState` includes `SwapIntoReturnDone` without - /// `ActiveSwapIntoReturnCurrency`: Prepare "executed decrease" hook & - /// transition state into its form without `SwapIntoReturnDone`. If the - /// state is just `SwapIntoReturnDone`, kill it. + /// 1. If the `InvestState` includes `SwapIntoForeignDone` without + /// `ActiveSwapIntoForeignCurrency`: Prepare "executed decrease" hook & + /// transition state into its form without `SwapIntoForeignDone`. If the + /// state is just `SwapIntoForeignDone`, kill it. /// /// 2. Update the `InvestmentState` storage. This step is required as the /// next step reads this storage entry. @@ -330,8 +333,8 @@ impl Pallet { /// /// 5. If the token swap handling resulted in a new `RedeemState`, update /// `RedemptionState` again. If the corresponding new `InnerRedeemState` - /// includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency`, - /// remove the `SwapIntoReturnDone` part or kill it. Additionally, emit + /// includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency`, + /// remove the `SwapIntoForeignDone` part or kill it. Additionally, emit /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 6. Update the investment. This also includes setting it to zero. We @@ -366,20 +369,20 @@ impl Pallet { Ok((state, None, invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrency { swap } | - InvestState::ActiveSwapIntoReturnCurrency { swap } | - // We don't care about `done_amount` until swap into return is fulfilled - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { + InvestState::ActiveSwapIntoForeignCurrency { swap } | + // We don't care about `done_amount` until swap into foreign is fulfilled + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { InvestmentState::::insert(who, investment_id, state); Ok((state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | - InvestState::ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { swap, invest_amount } | - // We don't care about `done_amount` until swap into return is fulfilled - InvestState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap,invest_amount, .. } => { + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, invest_amount } | + // We don't care about `done_amount` until swap into foreign is fulfilled + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap,invest_amount, .. } => { InvestmentState::::insert(who, investment_id, state); Ok((state, Some(swap), invest_amount)) }, - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, done_amount } => { maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; @@ -387,7 +390,7 @@ impl Pallet { Ok((new_state, Some(swap), Zero::zero())) }, - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, invest_amount } => { maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; @@ -395,14 +398,14 @@ impl Pallet { Ok((new_state, Some(swap), invest_amount)) }, - InvestState::SwapIntoReturnDone { done_swap } => { + InvestState::SwapIntoForeignDone { done_swap } => { maybe_executed_decrease = Some((done_swap.currency_in, done_swap.amount)); InvestmentState::::remove(who, investment_id); Ok((InvestState::NoState, None, Zero::zero())) }, - InvestState::SwapIntoReturnDoneAndInvestmentOngoing { done_swap, invest_amount } => { + InvestState::SwapIntoForeignDoneAndInvestmentOngoing { done_swap, invest_amount } => { maybe_executed_decrease = Some((done_swap.currency_in, done_swap.amount)); let new_state = InvestState::InvestmentOngoing { invest_amount }; @@ -426,8 +429,8 @@ impl Pallet { T::Investment::update_investment(who, investment_id, invest_amount)?; // Send notification after updating invest as else funds are still locked in investment account - if let Some((return_currency, decreased_amount)) = maybe_executed_decrease { - Self::notify_executed_decrease_invest(who, investment_id, return_currency, decreased_amount)?; + if let Some((foreign_currency, decreased_amount)) = maybe_executed_decrease { + Self::notify_executed_decrease_invest(who, investment_id, foreign_currency, decreased_amount)?; } @@ -442,9 +445,9 @@ impl Pallet { /// /// The following execution order must not be changed: /// - /// 1. If the `RedeemState` includes `SwapIntoReturnDone` without - /// `ActiveSwapIntoReturnCurrency`, remove the `SwapIntoReturnDone` part or - /// kill it. + /// 1. If the `RedeemState` includes `SwapIntoForeignDone` without + /// `ActiveSwapIntoForeignCurrency`, remove the `SwapIntoForeignDone` part + /// or kill it. /// /// 2. Update the `RedemptionState` storage. This step is required as the /// next step reads this storage entry. @@ -456,8 +459,8 @@ impl Pallet { /// /// 4. If the token swap handling resulted in a new `RedeemState`, update /// `RedemptionState` again. If the corresponding new `InnerRedeemState` - /// includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency`, - /// remove the `SwapIntoReturnDone` part or kill it. Additionally, emit + /// includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency`, + /// remove the `SwapIntoForeignDone` part or kill it. Additionally, emit /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 5. If the token swap handling resulted in a new `InvestState`, @@ -498,18 +501,18 @@ impl Pallet { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), None)) }, - InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } | - InnerRedeemState::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | - InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - InnerRedeemState::ActiveSwapIntoReturnCurrency { swap, .. } | - InnerRedeemState::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | - InnerRedeemState::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => { + InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } | + InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | + InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + InnerRedeemState::ActiveSwapIntoForeignCurrency { swap, .. } | + InnerRedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + InnerRedeemState::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | + InnerRedeemState::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), Some(swap))) }, - // Only states left include `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` such that we can notify collect + // Only states left include `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` such that we can notify collect inner => { let maybe_new_state = Self::apply_collect_redeem_transition(who, investment_id, state, inner)?; Ok((maybe_new_state, None)) @@ -591,11 +594,11 @@ impl Pallet { } } - /// Terminates a redeem collection which required swapping into return + /// Terminates a redeem collection which required swapping into foreign /// currency. /// - /// Only acts upon inner redeem states which include `SwapIntoReturnDone` - /// without `ActiveSwapIntoReturnCurrency`. Other inner states are ignored. + /// Only acts upon inner redeem states which include `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency`. Other inner states are ignored. /// Either updates the corresponding `RedemptionState` or drops it entirely. /// /// Emits `notify_executed_collect_redeem`. @@ -618,15 +621,15 @@ impl Pallet { CollectedRedemptionTrancheTokens::::get(who, investment_id); // Send notification and kill `CollectedRedemptionTrancheTokens` iff the state - // includes `SwapIntoReturnDone` without `ActiveSwapIntoReturnCurrency` + // includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` match inner_redeem_state { - InnerRedeemState::SwapIntoReturnDone { done_swap, .. } - | InnerRedeemState::RedeemingAndSwapIntoReturnDone { done_swap, .. } - | InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + InnerRedeemState::SwapIntoForeignDone { done_swap, .. } + | InnerRedeemState::RedeemingAndSwapIntoForeignDone { done_swap, .. } + | InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } - | InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => { + | InnerRedeemState::CollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => { Self::notify_executed_collect_redeem( who, investment_id, @@ -643,20 +646,20 @@ impl Pallet { } .map_err(|e: DispatchError| e)?; - // Update state iff the state includes `SwapIntoReturnDone` without - // `ActiveSwapIntoReturnCurrency` + // Update state iff the state includes `SwapIntoForeignDone` without + // `ActiveSwapIntoForeignCurrency` match inner_redeem_state { - InnerRedeemState::SwapIntoReturnDone { .. } => { + InnerRedeemState::SwapIntoForeignDone { .. } => { RedemptionState::::remove(who, investment_id); Ok(Some(RedeemState::NoState)) } - InnerRedeemState::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } => { + InnerRedeemState::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } => { let new_state = state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } - InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, .. } => { @@ -667,7 +670,7 @@ impl Pallet { RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } - InnerRedeemState::CollectableRedemptionAndSwapIntoReturnDone { .. } => { + InnerRedeemState::CollectableRedemptionAndSwapIntoForeignDone { .. } => { let new_state = state.swap_inner_state(InnerRedeemState::CollectableRedemption); RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) @@ -729,9 +732,9 @@ impl Pallet { }); // Need to check if `SwapReturnDone` is part of inner state without - // `ActiveSwapIntoReturnCurrency` as this implies the successful termination of - // a collect (with swap into return currency). If this is the case, the returned - // redeem state needs to be updated as well. + // `ActiveSwapIntoForeignCurrency` as this implies the successful termination of + // a collect (with swap into foreign currency). If this is the case, the + // returned redeem state needs to be updated as well. match maybe_redeem_state { Some(RedeemState::InvestedAnd { inner, .. }) | Some(RedeemState::NotInvestedAnd { inner }) => { @@ -846,19 +849,19 @@ impl Pallet { /// InvestmentId)` pair whereas investments and redemptions can both mutate /// orders. Assume, as a result of an `InvestState` transition, a token swap /// order into pool currency is initialized. Then, as a result of a - /// `RedeemState` transition, a token swap order into return currency is + /// `RedeemState` transition, a token swap order into foreign currency is /// needed. This handler resolves the _merge conflict_ in situations where /// the reason to create/update a swap order does not match the previous /// reason. /// /// * Is noop, if the the current reason equals the previous one. - /// * If both states are swapping into return currency, i.e. their invest - /// and redeem states include `ActiveSwapIntoReturnCurrency`, the states + /// * If both states are swapping into foreign currency, i.e. their invest + /// and redeem states include `ActiveSwapIntoForeignCurrency`, the states /// stay the same. However the total order amount needs to be updated by /// summing up both swap order amounts. /// * If the `InvestState` includes swapping into pool currency, i.e. /// `ActiveSwapIntoPoolCurrency`, whereas the `RedeemState` is swapping - /// into the opposite direction, i.e. `ActiveSwapIntoReturnCurrency`, we + /// into the opposite direction, i.e. `ActiveSwapIntoForeignCurrency`, we /// need to resolve the delta between both swap order amounts and update /// the states accordingly. #[allow(clippy::type_complexity)] @@ -904,11 +907,11 @@ impl Pallet { // Determine new invest state let new_invest_state = match invest_state { - // As redeem swap can only be into return currency, we need to delta on the opposite + // As redeem swap can only be into foreign currency, we need to delta on the opposite // swap directions InvestState::ActiveSwapIntoPoolCurrency { swap } => { if invest_swap_amount > redeem_swap_amount { - Ok(Some( + Some( InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { amount: swap_amount_opposite_direction, @@ -916,11 +919,11 @@ impl Pallet { }, invest_amount: resolved_amount, }, - )) + ) } else { - Ok(Some(InvestState::InvestmentOngoing { + Some(InvestState::InvestmentOngoing { invest_amount: resolved_amount, - })) + }) } } // Same as above except for the base investment amount which is incremented @@ -929,7 +932,7 @@ impl Pallet { invest_amount, } => { if invest_swap_amount > redeem_swap_amount { - Ok(Some( + Some( InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { amount: swap_amount_opposite_direction, @@ -937,17 +940,16 @@ impl Pallet { }, invest_amount: invest_amount.ensure_add(resolved_amount)?, }, - )) + ) } else { - Ok(Some(InvestState::InvestmentOngoing { + Some(InvestState::InvestmentOngoing { invest_amount: invest_amount.ensure_add(resolved_amount)?, - })) + }) } } // We must not alter the invest state if there is no active pool currency swap - _ => Ok(None), - } - .map_err(|e: DispatchError| e)?; + _ => None, + }; // Determine final swap amount and new redeem state let (final_swap_amount, new_redeem_state) = match invest_state { @@ -963,7 +965,7 @@ impl Pallet { Ok((swap_amount_opposite_direction, new_state)) } // All leftover combinations either do not involve any active swaps or both - // swaps have the same direction, i.e. into return currency. Thus, we can + // swaps have the same direction, i.e. into foreign currency. Thus, we can // leave states untouched and just add up the potential swap amount. _ => Ok(( invest_swap_amount.ensure_add(redeem_swap_amount)?, @@ -1007,7 +1009,7 @@ impl Pallet { fn notify_executed_decrease_invest( who: &T::AccountId, investment_id: T::InvestmentId, - return_currency: T::CurrencyId, + foreign_currency: T::CurrencyId, amount_decreased: T::Balance, ) -> DispatchResult { T::ExecutedDecreaseInvestHook::notify_status_change( @@ -1019,7 +1021,7 @@ impl Pallet { }, ExecutedForeignDecrease { amount_decreased, - return_currency, + foreign_currency, }, ) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 69d25f9379..8dbe3e820c 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -21,17 +21,17 @@ use sp_runtime::{ use crate::types::{ InnerRedeemState, InnerRedeemState::{ - ActiveSwapIntoReturnCurrency, ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - CollectableRedemption, CollectableRedemptionAndActiveSwapIntoReturnCurrency, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - CollectableRedemptionAndSwapIntoReturnDone, Redeeming, - RedeemingAndActiveSwapIntoReturnCurrency, - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, + ActiveSwapIntoForeignCurrency, ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, + CollectableRedemption, CollectableRedemptionAndActiveSwapIntoForeignCurrency, + CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, + CollectableRedemptionAndSwapIntoForeignDone, Redeeming, + RedeemingAndActiveSwapIntoForeignCurrency, + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, RedeemingAndCollectableRedemption, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone, - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone, RedeemingAndSwapIntoReturnDone, - SwapIntoReturnDone, + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency, + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone, RedeemingAndSwapIntoForeignDone, + SwapIntoForeignDone, }, RedeemState, RedeemTransition, }; @@ -63,10 +63,10 @@ where } } - /// Returns the potentially existing active swap into return currency of the - /// inner state: - /// * If the inner state includes `ActiveSwapIntoReturnCurrency`, it returns - /// the corresponding `Some(swap)`. + /// Returns the potentially existing active swap into foreign currency of + /// the inner state: + /// * If the inner state includes `ActiveSwapIntoForeignCurrency`, it + /// returns the corresponding `Some(swap)`. /// * Else, it returns `None`. pub(crate) fn get_active_swap(&self) -> Option> { match self { @@ -114,18 +114,18 @@ where } } - /// Reduce the amount of an active swap (into return currency) of the + /// Reduce the amount of an active swap (into foreign currency) of the /// `InnerRedeemState` by the provided value: /// * If the provided value equals the swap amount, the state is - /// transitioned into `*AndSwapIntoReturnDone`. + /// transitioned into `*AndSwapIntoForeignDone`. /// * Else, it is transitioned into - /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. /// /// NOTE: Throws if any of the following holds true: /// * The outer `RedeemState` is not `InvestedAnd` or `NotInvested` as this /// implies there is no active swap. /// * The inner state is not an active swap, i.e. the state does not include - /// `ActiveSwapIntoReturnCurrency`. + /// `ActiveSwapIntoForeignCurrency`. /// * The reducible amount exceeds the active swap amount. pub(crate) fn fulfill_active_swap_amount( &self, @@ -179,20 +179,20 @@ where Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, Currency: Clone + Copy + PartialEq + Debug, { - /// Returns the potentially existing active swap into return currency: - /// * If the state includes `ActiveSwapIntoReturnCurrency`, it returns the + /// Returns the potentially existing active swap into foreign currency: + /// * If the state includes `ActiveSwapIntoForeignCurrency`, it returns the /// corresponding `Some(swap)`. /// * Else, it returns `None`. fn get_active_swap(&self) -> Option> { match *self { - Self::ActiveSwapIntoReturnCurrency { swap } | - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - Self::RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } | - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } | - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } | - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, .. } => Some(swap), + Self::ActiveSwapIntoForeignCurrency { swap } | + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } | + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), _ => None, } } @@ -202,33 +202,33 @@ where match *self { Self::Redeeming { redeem_amount } | Self::RedeemingAndCollectableRedemption { redeem_amount, .. } | - Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, .. } | - Self::RedeemingAndSwapIntoReturnDone { redeem_amount, .. } | - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, .. } => redeem_amount, + Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, .. } | + Self::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } | + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, .. } | + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, .. } => redeem_amount, _ => Balance::zero(), } } - /// Reduce the amount of an active swap (into return currency) by the + /// Reduce the amount of an active swap (into foreign currency) by the /// provided value: /// * Throws if there is no active swap, i.e. the state does not include - /// `ActiveSwapIntoReturnCurrency` or if the reducible amount exceeds the + /// `ActiveSwapIntoForeignCurrency` or if the reducible amount exceeds the /// swap amount /// * If the provided value equals the swap amount, the state is - /// transitioned into `*AndSwapIntoReturnDone`. + /// transitioned into `*AndSwapIntoForeignDone`. /// * Else, it is transitioned into - /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. fn fulfill_active_swap_amount(&self, amount: Balance) -> Result { match self { - Self::ActiveSwapIntoReturnCurrency { swap } => { + Self::ActiveSwapIntoForeignCurrency { swap } => { if amount == swap.amount{ - Ok(Self::SwapIntoReturnDone { done_swap: *swap }) + Ok(Self::SwapIntoForeignDone { done_swap: *swap }) } else { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -238,12 +238,12 @@ where ) } }, - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { Ok( - Self::SwapIntoReturnDone { + Self::SwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..*swap @@ -252,7 +252,7 @@ where ) } else { Ok( - Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -262,10 +262,10 @@ where ) } }, - Self::RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { if amount == swap.amount { Ok( - Self::RedeemingAndSwapIntoReturnDone { + Self::RedeemingAndSwapIntoForeignDone { done_swap: Swap { amount, ..*swap @@ -275,7 +275,7 @@ where ) } else { Ok( - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -286,12 +286,12 @@ where ) } }, - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { Ok( - Self::RedeemingAndSwapIntoReturnDone { + Self::RedeemingAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..*swap @@ -301,7 +301,7 @@ where ) } else { Ok( - Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -312,17 +312,17 @@ where ) } }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { if amount == swap.amount { Ok( - Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: *swap, redeem_amount: *redeem_amount, } ) } else { Ok( - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -333,12 +333,12 @@ where ) } }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { Ok( - Self::RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..*swap @@ -348,7 +348,7 @@ where ) } else { Ok( - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -359,16 +359,16 @@ where ) } }, - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { if amount == swap.amount { Ok( - Self::CollectableRedemptionAndSwapIntoReturnDone { + Self::CollectableRedemptionAndSwapIntoForeignDone { done_swap: *swap, } ) } else { Ok( - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -378,12 +378,12 @@ where ) } }, - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { Ok( - Self::CollectableRedemptionAndSwapIntoReturnDone { + Self::CollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..*swap @@ -392,7 +392,7 @@ where ) } else { Ok( - Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_sub(amount)?, ..*swap @@ -413,12 +413,12 @@ where match *self { Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), RedeemingAndCollectableRedemption { .. } => Ok(CollectableRedemption), - RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(ActiveSwapIntoReturnCurrency { swap }), - RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(SwapIntoReturnDone { done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount }), + RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(ActiveSwapIntoForeignCurrency { swap }), + RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(SwapIntoForeignDone { done_swap }), + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap }), + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), // Throw for states without `Redeeming` _ => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), } @@ -441,19 +441,19 @@ where match *self { Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - ActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), - SwapIntoReturnDone { done_swap } => Ok(RedeemingAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, redeem_amount: amount }), - CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, redeem_amount: amount }), + ActiveSwapIntoForeignCurrency { swap } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { swap, redeem_amount: amount }), + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, redeem_amount: amount }), + SwapIntoForeignDone { done_swap } => Ok(RedeemingAndSwapIntoForeignDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, redeem_amount: amount }), + CollectableRedemptionAndSwapIntoForeignDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, redeem_amount: amount }), + CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, redeem_amount: amount }), } } @@ -467,29 +467,29 @@ where match *self { Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), + RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), _ => Err(DispatchError::Other("Cannot set existing redeem amount of inner redeem state which does not include `Redeeming`")), } } /// Transition all inner states which include - /// `ActiveSwapIntoReturnCurrency`. The transitioned state either includes - /// `*SwapIntoReturnDone` or - /// `*ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone`. + /// `ActiveSwapIntoForeignCurrency`. The transitioned state either includes + /// `*SwapIntoForeignDone` or + /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. /// /// Also supports non-foreign swaps, i.e. those with matching in and out /// currency. /// - /// Throws if the fulfilled swap direction is not into return currency or if - /// the amount exceeds the states active swap amount. + /// Throws if the fulfilled swap direction is not into foreign currency or + /// if the amount exceeds the states active swap amount. /// /// NOTE: We can ignore all states which do not include - /// `ActiveSwapIntoReturnCurrency`. + /// `ActiveSwapIntoForeignCurrency`. fn transition_fulfilled_swap_order( &self, fulfilled_swap: Swap, @@ -512,64 +512,64 @@ where // Edge case: if currency_in matches currency_out, we can immediately fulfill // the swap match *self { - ActiveSwapIntoReturnCurrency { swap } => { + ActiveSwapIntoForeignCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) + Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) } else { - Ok(SwapIntoReturnDone { done_swap: swap }) + Ok(SwapIntoForeignDone { done_swap: swap }) } }, - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) + Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) } else { - Ok(SwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) + Ok(SwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap } }) } }, - RedeemingAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) + Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) } else { - Ok(RedeemingAndSwapIntoReturnDone { done_swap: swap, redeem_amount }) + Ok(RedeemingAndSwapIntoForeignDone { done_swap: swap, redeem_amount }) } }, - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) + Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) } else { - Ok(RedeemingAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) + Ok(RedeemingAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: swap, redeem_amount }) + Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: swap, redeem_amount }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) + Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) + Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { + CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) + Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) } else { - Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: swap }) + Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap: swap }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) + Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) } else { - Ok(CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap { amount: done_amount, ..swap } }) + Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap } }) } }, _ => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), @@ -578,7 +578,7 @@ where /// Apply the transition of the state after collecting a redemption: /// * If the collected amount (in pool currency) is positive, this indicates - /// that we need to initiate the swap into return currency + /// that we need to initiate the swap into foreign currency /// * If the collected amount is zero, this indicates that the collection is /// considered to be done. /// @@ -586,7 +586,7 @@ where /// * The current state includes an active/done swap and in and out /// currencies do not match the provided ones; or /// * The collected amount is zero but the state does not include a foreign - /// `ActiveSwapIntoReturnCurrency` or `SwapIntoReturnDone` + /// `ActiveSwapIntoForeignCurrency` or `SwapIntoForeignDone` fn transition_collect( &self, collected_swap: Swap, @@ -610,7 +610,7 @@ where if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap: collected_swap, }) } @@ -619,21 +619,21 @@ where if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap: collected_swap, }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { redeem_amount, swap } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { if collected_swap.amount.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrency { + Ok(Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap }) } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, @@ -642,14 +642,14 @@ where }) } }, - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { redeem_amount, done_swap } => { + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, done_swap } => { if collected_swap.amount.is_zero() { - Ok(Self::RedeemingAndSwapIntoReturnDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { redeem_amount, done_swap, }) } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap: Swap { amount: collected_swap.amount, @@ -659,15 +659,15 @@ where }) } }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { redeem_amount, swap, done_amount } => { + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { if collected_swap.amount.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount }) } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, @@ -677,13 +677,13 @@ where }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap } => { + CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { if collected_swap.amount.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrency { + Ok(Self::ActiveSwapIntoForeignCurrency { swap, }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrency { + Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap @@ -691,13 +691,13 @@ where }) } }, - CollectableRedemptionAndSwapIntoReturnDone { done_swap } => { + CollectableRedemptionAndSwapIntoForeignDone { done_swap } => { if collected_swap.amount.is_zero() { - Ok(Self::SwapIntoReturnDone { + Ok(Self::SwapIntoForeignDone { done_swap, }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: collected_swap.amount, ..collected_swap @@ -706,14 +706,14 @@ where }) } }, - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { swap, done_amount } => { + CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { if collected_swap.amount.is_zero() { - Ok(Self::ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap @@ -730,11 +730,11 @@ where /// non-foreign currencies. /// * Ignores any states without `CollectableRedemption`. /// * Throws for all states with `CollectableRedemption` and - /// `ActiveSwapIntoReturnCurrency` as there can't be an active swap for + /// `ActiveSwapIntoForeignCurrency` as there can't be an active swap for /// non-foreign currencies, these should immediately fulfilled. - /// * Else replaces `CollectableRedemption` with `SwapIntoReturnDone` if it - /// did not exist already. If it did, increment the done swap amount by - /// the collected one. + /// * Else replaces `CollectableRedemption` with `SwapIntoForeignDone` if + /// it did not exist already. If it did, increment the done swap amount + /// by the collected one. fn transition_collect_non_foreign( &self, collected_swap: Swap, @@ -744,7 +744,7 @@ where if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) } else { - Ok(Self::CollectableRedemptionAndSwapIntoReturnDone { + Ok(Self::CollectableRedemptionAndSwapIntoForeignDone { done_swap: collected_swap, }) } @@ -753,24 +753,24 @@ where if collected_swap.amount.is_zero() { Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) } else { - Ok(Self::RedeemingAndSwapIntoReturnDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { redeem_amount, done_swap: collected_swap, }) } } - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, done_swap, - } => Ok(RedeemingAndSwapIntoReturnDone { + } => Ok(RedeemingAndSwapIntoForeignDone { redeem_amount, done_swap: Swap { amount: done_swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap }, }), - CollectableRedemptionAndSwapIntoReturnDone { done_swap } => Ok(SwapIntoReturnDone { + CollectableRedemptionAndSwapIntoForeignDone { done_swap } => Ok(SwapIntoForeignDone { done_swap: Swap { amount: done_swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap @@ -907,7 +907,7 @@ where } } - /// Update the inner state if it includes `ActiveSwapIntoReturnCurrency`. + /// Update the inner state if it includes `ActiveSwapIntoForeignCurrency`. fn handle_fulfilled_swap_order( &self, swap: Swap, @@ -930,7 +930,7 @@ where } /// Remove `CollectableRedemption` from all inner states which include it. - /// Either swap it with `ActiveSwapIntoReturnCurrency` if the inner state + /// Either swap it with `ActiveSwapIntoForeignCurrency` if the inner state /// did not include an active swap or simply drop it. /// /// Throws if the state does not allow for collection or the the inner state diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 479047fb50..a9e9b25d00 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -58,8 +58,8 @@ pub enum InvestState< /// The investment is currently swapped into the required pool currency. ActiveSwapIntoPoolCurrency { swap: Swap }, /// The unprocessed investment was fully decreased and is currently swapped - /// back into the corresponding return currency. - ActiveSwapIntoReturnCurrency { swap: Swap }, + /// back into the corresponding foreign currency. + ActiveSwapIntoForeignCurrency { swap: Swap }, /// The investment is not fully swapped into pool currency and thus split /// into two parts: /// * One part is still being swapped. @@ -70,69 +70,70 @@ pub enum InvestState< }, /// The investment is split into two parts: /// * One part is waiting to be processed as investment. - /// * The remainder is swapped back into the return currency as a result of + /// * The remainder is swapped back into the foreign currency as a result of /// decreasing the invested amount before being processed. - ActiveSwapIntoReturnCurrencyAndInvestmentOngoing { + ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: Swap, invest_amount: Balance, }, /// The investment is split into two parts: /// * The one part is swapping into pool currency. - /// * The remainder was swapped back into the return currency as a result of - /// decreasing the invested amount before being processed. + /// * The remainder was swapped back into the foreign currency as a result + /// of decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into `ActiveSwapIntoPoolCurrency` - /// by applying the corresponding trigger to handle the return amount. - ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDone { + /// by applying the corresponding trigger to handle the foreign return + /// amount. + ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap: Swap, done_amount: Balance, }, - /// The investment is swapped back into the return currency and was already + /// The investment is swapped back into the foreign currency and was already /// partially fulfilled. - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap, done_amount: Balance, }, /// The investment is split into three parts: /// * One part is currently swapping into the pool currency. /// * The second is already waiting to be processed as investment. - /// * The remainder was swapped back into the return currency as a result of - /// decreasing the invested amount before being processed. + /// * The remainder was swapped back into the foreign currency as a result + /// of decreasing the invested amount before being processed. /// /// NOTE: This state can be transitioned into /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` by applying the - /// corresponding trigger to handle the return amount. - ActiveSwapIntoPoolCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + /// corresponding trigger to handle the foreign return amount. + ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap, done_amount: Balance, invest_amount: Balance, }, /// The investment is split into three parts: /// * One is waiting to be processed as investment. - /// * The second is swapped back into the return currency as a result of + /// * The second is swapped back into the foreign currency as a result of /// decreasing the invested amount before being processed. - /// * The remainder was already swapped back into the return currency. + /// * The remainder was already swapped back into the foreign currency. /// /// NOTE: This state should not be transitioned by applying the trigger for /// the done part but wait until the active swap is fulfilled. - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDoneAndInvestmentOngoing { + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap, done_amount: Balance, invest_amount: Balance, }, - /// The unprocessed investment was swapped back into return currency. + /// The unprocessed investment was swapped back into foreign currency. /// /// NOTE: This state can be killed by applying the corresponding trigger to - /// handle the return amount. - SwapIntoReturnDone { done_swap: Swap }, + /// handle the foreign return amount. + SwapIntoForeignDone { done_swap: Swap }, /// The investment is split into two parts: /// * One part is waiting to be processed as an investment - /// * The swapped back into the return currency as a result of decreasing + /// * The swapped back into the foreign currency as a result of decreasing /// the invested amount before being processed. /// /// NOTE: This state can be transitioned into `InvestmentOngoing` by - /// applying the corresponding trigger to handle the return amount. - SwapIntoReturnDoneAndInvestmentOngoing { + /// applying the corresponding trigger to handle the foreign return amount. + SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap, invest_amount: Balance, }, @@ -148,14 +149,14 @@ pub enum InvestTransition< > { /// Assumes `swap.currency_in` is pool currency as we increase here. IncreaseInvestOrder(Swap), - /// Assumes `swap.currency_in` is return currency as we decrease here. + /// Assumes `swap.currency_in` is foreign currency as we decrease here. DecreaseInvestOrder(Swap), /// Implicitly derives `swap.currency_in` and `swap.currency_out` from /// previous state: /// * If the previous state includes `ActiveSwapIntoPoolCurrency`, /// `currency_in` is the pool currency. - /// * If the previous state includes `ActiveSwapIntoReturnCurrency`, - /// `currency_in` is the return currency. + /// * If the previous state includes `ActiveSwapIntoForeignCurrency`, + /// `currency_in` is the foreign currency. FulfillSwapOrder(Swap), EpochExecution(Balance), } @@ -221,45 +222,45 @@ pub enum InnerRedeemState< /// redemption and a collectable amount. RedeemingAndCollectableRedemption { redeem_amount: Balance }, /// The redemption was fully processed and collected and is currently - /// swapping into the return currency. - ActiveSwapIntoReturnCurrency { swap: Swap }, + /// swapping into the foreign currency. + ActiveSwapIntoForeignCurrency { swap: Swap }, /// The redemption was fully processed, collected and partially swapped into - /// the return currency. It is split into two parts: - /// * One part is swapping back into the return currency. + /// the foreign currency. It is split into two parts: + /// * One part is swapping back into the foreign currency. /// * The remainder was already swapped back. - ActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap, done_amount: Balance, }, /// The redemption was fully processed, collected and swapped into the - /// return currency. + /// foreign currency. /// /// NOTE: This state does not require handling in `RedeemState::transition` /// as it must be manually transitioned in `apply_redeem_state_transition`, /// similar to the corresponding state in `InvestState`. - SwapIntoReturnDone { done_swap: Swap }, + SwapIntoForeignDone { done_swap: Swap }, /// The redemption is split into two parts: /// * One part is waiting to be processed as redemption. - /// * The remainder is swapping back into the return currency as a result of - /// processing and collecting beforehand. - RedeemingAndActiveSwapIntoReturnCurrency { + /// * The remainder is swapping back into the foreign currency as a result + /// of processing and collecting beforehand. + RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount: Balance, swap: Swap, }, /// The redemption is split into two parts: /// * One part is waiting to be processed as redemption. - /// * The remainder is swapping back into the return currency as a result of - /// processing and collecting beforehand. - RedeemingAndSwapIntoReturnDone { + /// * The remainder is swapping back into the foreign currency as a result + /// of processing and collecting beforehand. + RedeemingAndSwapIntoForeignDone { redeem_amount: Balance, done_swap: Swap, }, /// The redemption is split into three parts: /// * One part is waiting to be processed as redemption. - /// * The second is swapping back into the return currency as a result of + /// * The second is swapping back into the foreign currency as a result of /// processing and collecting beforehand. /// * The remainder was already swapped back. - RedeemingAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: Balance, swap: Swap, done_amount: Balance, @@ -267,48 +268,48 @@ pub enum InnerRedeemState< /// The redemption is split into three parts: /// * One part is waiting to be processed as redemption. /// * The second is waiting to be collected. - /// * The remainder is swapping back into the return currency as a result of - /// processing and collecting beforehand. - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrency { + /// * The remainder is swapping back into the foreign currency as a result + /// of processing and collecting beforehand. + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount: Balance, swap: Swap, }, /// The redemption is split into three parts: /// * One part is waiting to be processed as redemption. /// * The second is waiting to be collected. - /// * The remainder was successfully swapped back into the return currency + /// * The remainder was successfully swapped back into the foreign currency /// as a result of processing and collecting beforehand. - RedeemingAndCollectableRedemptionAndSwapIntoReturnDone { + RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount: Balance, done_swap: Swap, }, /// The redemption is split into four parts: /// * One part is waiting to be processed as redemption. /// * The second is waiting to be collected. - /// * The third part is swapping back into the return currency as a result + /// * The third part is swapping back into the foreign currency as a result /// of processing and collecting beforehand /// * The remainder was already swapped back. - RedeemingAndCollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: Balance, swap: Swap, done_amount: Balance, }, /// The redemption is split into two parts: /// * One part is waiting to be collected. - /// * The remainder is swapping back into the return currency as a result of - /// processing and collecting beforehand. - CollectableRedemptionAndActiveSwapIntoReturnCurrency { swap: Swap }, + /// * The remainder is swapping back into the foreign currency as a result + /// of processing and collecting beforehand. + CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap: Swap }, /// The redemption is split into two parts: /// * One part is waiting to be collected. - /// * The remainder was successfully swapped back into the return currency + /// * The remainder was successfully swapped back into the foreign currency /// as a result of processing and collecting beforehand. - CollectableRedemptionAndSwapIntoReturnDone { done_swap: Swap }, + CollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap }, /// The redemption is split into three parts: /// * One part is waiting to be collected. - /// * The second is swapping back into the return currency as a result of + /// * The second is swapping back into the foreign currency as a result of /// processing and collecting beforehand /// * The remainder was already swapped back. - CollectableRedemptionAndActiveSwapIntoReturnCurrencyAndSwapIntoReturnDone { + CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap, done_amount: Balance, }, diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 953e69b9b4..1650356922 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -49,11 +49,11 @@ where owner: investor, .. } = id; - let currency = Pallet::::try_get_general_index(status.return_currency)?; - let wrapped_token = Pallet::::try_get_wrapped_token(&status.return_currency)?; + let currency = Pallet::::try_get_general_index(status.foreign_currency)?; + let wrapped_token = Pallet::::try_get_wrapped_token(&status.foreign_currency)?; let domain_address: DomainAddress = wrapped_token.into(); - T::Tokens::burn_from(status.return_currency, &investor, status.amount_decreased)?; + T::Tokens::burn_from(status.foreign_currency, &investor, status.amount_decreased)?; let message: MessageOf = Message::ExecutedDecreaseInvestOrder { pool_id: investment_id.of_pool(), diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 7a4358fb8a..26e5bf360a 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -123,11 +123,11 @@ where /// Initiates the decrement of an existing investment order of the investor. /// /// On success, the unprocessed investment amount is decremented and a swap - /// back into the provided return currency initiated. + /// back into the provided foreign currency initiated. /// /// The finalization of this call (fulfillment of the swap) is assumed to be /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` - /// which burns the corresponding amount in return currency and dispatches + /// which burns the corresponding amount in foreign currency and dispatches /// `ExecutedDecreaseInvestOrder`. pub fn handle_decrease_invest_order( pool_id: T::PoolId, @@ -155,11 +155,11 @@ where /// Cancels an invest order by decreasing by the entire unprocessed /// investment amount. /// - /// On success, initiates a swap back into the provided return currency. + /// On success, initiates a swap back into the provided foreign currency. /// /// The finalization of this call (fulfillment of the swap) is assumed to be /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` - /// which burns the corresponding amount in return currency and dispatches + /// which burns the corresponding amount in foreign currency and dispatches /// `ExecutedDecreaseInvestOrder`. pub fn handle_cancel_invest_order( pool_id: T::PoolId, @@ -336,7 +336,7 @@ where /// directly appended to the next active order for this investment. /// /// On success, a swap will be initiated to exchange the (partially) - /// collected amount in pool currency into the desired return currency. + /// collected amount in pool currency into the desired foreign currency. /// /// The termination of this call (fulfillment of the swap) is assumed to be /// asynchronous and handled by the `CollectRedeemHook`. It burns the return From 3dc5100b787cdba4799907a9b64150a9954a352a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 22 Aug 2023 15:59:29 +0200 Subject: [PATCH 46/96] fix: integration tests --- Cargo.lock | 1 + pallets/foreign-investments/src/errors.rs | 6 +- .../foreign-investments/src/impls/invest.rs | 23 +- pallets/foreign-investments/src/impls/mod.rs | 96 +- .../foreign-investments/src/impls/redeem.rs | 406 +++---- pallets/foreign-investments/src/lib.rs | 85 +- pallets/foreign-investments/src/types.rs | 5 +- pallets/investments/src/lib.rs | 4 +- pallets/liquidity-pools/src/hooks.rs | 2 + pallets/liquidity-pools/src/inbound.rs | 2 + runtime/altair/src/lib.rs | 2 +- runtime/development/src/lib.rs | 2 +- runtime/integration-tests/Cargo.toml | 3 + .../development/tests/liquidity_pools.rs | 1071 +++++++++-------- 14 files changed, 792 insertions(+), 916 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fce710dbe6..cde53f06b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11019,6 +11019,7 @@ dependencies = [ "pallet-ethereum-transaction", "pallet-evm", "pallet-evm-chain-id", + "pallet-foreign-investments", "pallet-investments", "pallet-liquidity-pools", "pallet-liquidity-pools-gateway", diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index e23cc9aa68..619163e15a 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -23,9 +23,9 @@ pub enum InvestError { Decrease, /// Failed to transition after fulfilled swap order. FulfillSwapOrder, - /// Failed to transition a (partially) processed investment after an epoch - /// was executed. - EpochExecution, + /// Failed to transition a (partially) processed investment after + /// collecting. + Collect, } #[derive(Encode, Decode, TypeInfo, PalletError)] diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 90e9686ef9..d481424ea3 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -42,8 +42,8 @@ where InvestTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(self, swap) } - InvestTransition::EpochExecution(amount_unprocessed) => { - Self::handle_epoch_execution(self, amount_unprocessed) + InvestTransition::CollectInvestment(amount_unprocessed) => { + Self::handle_collect(self, amount_unprocessed) } } } @@ -848,11 +848,6 @@ where &self, swap: Swap, ) -> Result { - #[cfg(feature = "std")] - { - println!("Inside invest handle_decrease_non_foreign"); - dbg!(self, swap); - } if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { Ok(InvestState::SwapIntoForeignDoneAndInvestmentOngoing { @@ -872,14 +867,12 @@ where } } - /// Update or kill the unprocessed investment amount. - /// * If the state does not include `InvestmentOngoing` and the unprocessed - /// amount is not zero, there is nothing to transition, return the current - /// state. If the unprocessed amount is zero, state is corrupted. - /// * Else If the provided `unprocessed_amount` is zero, remove - /// `InvestmentOngoing` from the state - /// * Else set the `invest_amount` to `unprocessed_amount` - fn handle_epoch_execution(&self, unprocessed_amount: Balance) -> Result { + /// Update or kill the state's unprocessed investing amount. + /// * If the state includes `InvestmentOngoing`, either update or remove the + /// invested amount. + /// * Else the unprocessed amount should be zero. If it is not, state is + /// corrupted as this reflects the investment was increased improperly. + fn handle_collect(&self, unprocessed_amount: Balance) -> Result { match *self { Self::InvestmentOngoing { .. } => { if unprocessed_amount.is_zero() { diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 1fd82d8edb..7ad1ab8e11 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -57,7 +57,7 @@ impl StatusNotificationHook for Pallet { match reason { TokenSwapReason::Investment => { - let pre_state = InvestmentState::::get(&info.owner, info.id).unwrap_or_default(); + let pre_state = InvestmentState::::get(&info.owner, info.id); let post_state = pre_state .transition(InvestTransition::FulfillSwapOrder(status)) .map_err(|e| { @@ -68,7 +68,7 @@ impl StatusNotificationHook for Pallet { Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) } TokenSwapReason::Redemption => { - let pre_state = RedemptionState::::get(&info.owner, info.id).unwrap_or_default(); + let pre_state = RedemptionState::::get(&info.owner, info.id); let post_state = pre_state .transition(RedeemTransition::FulfillSwapOrder(status)) .map_err(|e| { @@ -97,7 +97,7 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); + let pre_state = InvestmentState::::get(who, investment_id); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production @@ -131,7 +131,7 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); + let pre_state = InvestmentState::::get(who, investment_id); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production @@ -163,7 +163,8 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result<(), DispatchError> { - let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); + let pre_state = + RedemptionState::::get(who, investment_id).increase_invested_amount(amount)?; // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production @@ -191,7 +192,7 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { - let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); + let pre_state = RedemptionState::::get(who, investment_id); // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be // removed before deploying to production @@ -223,6 +224,18 @@ impl ForeignInvestment for Pallet { amount_payment, } = T::Investment::collect_investment(who.clone(), investment_id)?; + // Update invest state + let pre_state = InvestmentState::::get(who, investment_id); + let investing_amount = T::Investment::investment(who, investment_id)?; + let post_state = + pre_state.transition(InvestTransition::CollectInvestment(investing_amount))?; + Self::apply_invest_state_transition(who, investment_id, post_state).map_err(|e| { + log::debug!("InvestState transition error: {:?}", e); + Error::::from(InvestError::Collect) + })?; + + // Determine payout amount in foreign currency instead of current pool currency + // denomination let amount_currency_payout = T::CurrencyConverter::stable_to_stable( pool_currency, amount_payment, @@ -250,13 +263,17 @@ impl ForeignInvestment for Pallet { })?; // Transition state to initiate swap from pool to foreign currency - let pre_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); + let pre_state = RedemptionState::::get(who, investment_id); + let amount_unprocessed_redemption = T::Investment::redemption(who, investment_id)?; let post_state = pre_state - .transition(RedeemTransition::Collect(SwapOf:: { - amount: collected.amount_collected, - currency_in: foreign_currency, - currency_out: pool_currency, - })) + .transition(RedeemTransition::CollectRedemption( + amount_unprocessed_redemption, + SwapOf:: { + amount: collected.amount_collected, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + )) .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("RedeemState transition error: {:?}", e); @@ -425,15 +442,16 @@ impl Pallet { } Self::deposit_redemption_event(who, investment_id, maybe_new_redeem_state); - // Update investment after all states have been updated - T::Investment::update_investment(who, investment_id, invest_amount)?; + if T::Investment::investment(who, investment_id)? != invest_amount { + // Finally, update investment after all states have been updated + T::Investment::update_investment(who, investment_id, invest_amount)?; + } // Send notification after updating invest as else funds are still locked in investment account if let Some((foreign_currency, decreased_amount)) = maybe_executed_decrease { Self::notify_executed_decrease_invest(who, investment_id, foreign_currency, decreased_amount)?; } - Ok(()) }) .map_err(|e: DispatchError| e)? @@ -481,7 +499,7 @@ impl Pallet { investment_id: T::InvestmentId, state: RedeemState, ) -> DispatchResult { - let invest_amount = state.get_invested_amount().unwrap_or_default(); + let redeeming_amount = state.get_redeeming_amount(); // Do first round of updates and forward state as well as swap match state { @@ -528,7 +546,7 @@ impl Pallet { TokenSwapReason::Redemption, )?; - // Dispatch transition event, post swap state has priority if it exists as it was the last transition + // Dispatch transition event, post swap state has priority if it exists as it is the result of the latest update if let Some(redeem_state_post_swap) = maybe_new_state_prio { Self::deposit_redemption_event(who, investment_id, Some(redeem_state_post_swap)); } else { @@ -536,8 +554,10 @@ impl Pallet { } Self::deposit_investment_event(who, investment_id, maybe_new_invest_state); - // Finally, update redemption after all states have been updated - T::Investment::update_redemption(who, investment_id, invest_amount)?; + if T::Investment::redemption(who, investment_id)? != redeeming_amount { + // Finally, update redemption after all states have been updated + T::Investment::update_redemption(who, investment_id, redeeming_amount)?; + } Ok(()) }) @@ -724,10 +744,8 @@ impl Pallet { // Update invest and redeem states if necessary InvestmentState::::mutate(who, investment_id, |current_invest_state| { // Should never occur but let's be safe - if let Some(InvestState::NoState) = maybe_invest_state { - *current_invest_state = None; - } else if maybe_invest_state != *current_invest_state { - *current_invest_state = maybe_invest_state; + if let Some(state) = maybe_invest_state { + *current_invest_state = state; } }); @@ -735,30 +753,34 @@ impl Pallet { // `ActiveSwapIntoForeignCurrency` as this implies the successful termination of // a collect (with swap into foreign currency). If this is the case, the // returned redeem state needs to be updated as well. - match maybe_redeem_state { + let returning_redeem_state = match maybe_redeem_state { Some(RedeemState::InvestedAnd { inner, .. }) | Some(RedeemState::NotInvestedAnd { inner }) => { - let redeem_state = maybe_redeem_state.unwrap_or_default(); - let maybe_collected_redeem_state = Self::apply_collect_redeem_transition( + if let Some(collected_redeem_state) = Self::apply_collect_redeem_transition( who, investment_id, - redeem_state, + maybe_redeem_state.unwrap_or_default(), inner, - )?; - Ok((maybe_invest_state, maybe_collected_redeem_state)) + )? { + Ok(Some(collected_redeem_state)) + } else { + Ok(maybe_redeem_state) + } } Some(_) => { RedemptionState::::mutate(who, investment_id, |current_redeem_state| { // Update and emit event on mismatch - if maybe_redeem_state != *current_redeem_state { - *current_redeem_state = maybe_redeem_state; + if let Some(state) = maybe_redeem_state { + *current_redeem_state = state } - }); - Ok((maybe_invest_state, maybe_redeem_state)) + Ok(maybe_redeem_state) + }) } - None => Ok((maybe_invest_state, maybe_redeem_state)), + None => Ok(maybe_redeem_state), } - .map_err(|e: DispatchError| e) + .map_err(|e: DispatchError| e)?; + + Ok((maybe_invest_state, returning_redeem_state)) } // Update to provided value, if not none else if let Some(swap_order) = maybe_swap { @@ -890,8 +912,8 @@ impl Pallet { } // Read states from storage and determine amounts - let invest_state = InvestmentState::::get(who, investment_id).unwrap_or_default(); - let redeem_state = RedemptionState::::get(who, investment_id).unwrap_or_default(); + let invest_state = InvestmentState::::get(who, investment_id); + let redeem_state = RedemptionState::::get(who, investment_id); let invest_swap_amount = invest_state .get_active_swap() .map(|s| s.amount) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 8dbe3e820c..4498c4d178 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -56,9 +56,8 @@ where RedeemTransition::FulfillSwapOrder(swap) => { Self::handle_fulfilled_swap_order(self, swap) } - RedeemTransition::Collect(swap) => Self::handle_collect(self, swap), - RedeemTransition::EpochExecution(amount_unprocessed) => { - Self::handle_epoch_execution(self, amount_unprocessed) + RedeemTransition::CollectRedemption(amount_redeeming, swap) => { + Self::handle_collect(self, amount_redeeming, swap) } } } @@ -89,14 +88,25 @@ where } } - /// Returns the potentially existing invest, i.e. the upper redemption - /// bound. - pub(crate) fn get_invested_amount(&self) -> Option { - match self { - Self::Invested { invest_amount } | Self::InvestedAnd { invest_amount, .. } => { - Some(*invest_amount) - } - _ => None, + pub(crate) fn increase_invested_amount(&self, amount: Balance) -> Result { + match *self { + Self::NoState => Ok(Self::Invested { + invest_amount: amount, + }), + Self::Invested { invest_amount } => Ok(Self::Invested { + invest_amount: invest_amount.ensure_add(amount)?, + }), + Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { + invest_amount: amount, + inner, + }), + Self::InvestedAnd { + invest_amount, + inner, + } => Ok(Self::InvestedAnd { + invest_amount: invest_amount.ensure_add(amount)?, + inner, + }), } } @@ -140,38 +150,6 @@ where )), } } - - /// Update or kill the unprocessed redemption amount of the inner state. - /// * If the outer state does not include an inner state with `Redeeming`, - /// there is nothing to transition, i.e. we return the current state - /// * Else If the provided `unprocessed_amount` is zero, remove `Redeeming` - /// from the inner state - /// * Else set the `redeem_amount` to `unprocessed_amount` - fn handle_epoch_execution(&self, amount_unprocessed: Balance) -> Result { - match *self { - RedeemState::NoState | RedeemState::Invested { .. } => Ok(*self), - RedeemState::NotInvestedAnd { inner } => match inner { - Redeeming { .. } if !amount_unprocessed.is_zero() => Ok(Self::Invested { - invest_amount: amount_unprocessed, - }), - state => Ok(RedeemState::NotInvestedAnd { - inner: state.set_existing_redeem_amount(amount_unprocessed)?, - }), - }, - RedeemState::InvestedAnd { - inner, - invest_amount, - } => match inner { - Redeeming { .. } if !amount_unprocessed.is_zero() => Ok(Self::Invested { - invest_amount: amount_unprocessed, - }), - state => Ok(RedeemState::InvestedAnd { - inner: state.set_existing_redeem_amount(amount_unprocessed)?, - invest_amount, - }), - }, - } - } } impl InnerRedeemState @@ -434,7 +412,7 @@ where /// * If the value is zero and the state includes `Redeeming`: Removes /// `Redeeming` from the state. /// * Else throws. - fn add_or_overwrite_redeem_amount(&self, amount: Balance) -> Result { + fn set_redeem_amount(&self, amount: Balance) -> Result { if amount.is_zero() { return Self::remove_redeem_amount(self); } @@ -457,26 +435,6 @@ where } } - /// Sets the redeeming amount of the state to the given amount. - /// - /// Throws if the the state does not include `Redeeming`. - fn set_existing_redeem_amount(&self, amount: Balance) -> Result { - if amount.is_zero() { - return Self::remove_redeem_amount(self); - } - match *self { - Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), - _ => Err(DispatchError::Other("Cannot set existing redeem amount of inner redeem state which does not include `Redeeming`")), - } - } - /// Transition all inner states which include /// `ActiveSwapIntoForeignCurrency`. The transitioned state either includes /// `*SwapIntoForeignDone` or @@ -576,21 +534,66 @@ where } } + /// Either update or remove the redeeming amount and add + /// `SwapIntoForeignDone` for the provided collected swap. + fn transition_collect_non_foreign( + &self, + amount_redeeming: Balance, + collected_swap: Swap, + ) -> Result { + match *self { + Redeeming { .. } => { + if amount_redeeming.is_zero() { + Ok(SwapIntoForeignDone { + done_swap: collected_swap, + }) + } else { + Ok(RedeemingAndSwapIntoForeignDone { + redeem_amount: amount_redeeming, + done_swap: collected_swap, + }) + } + } + RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + let swap = Swap { + amount: done_swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + + if amount_redeeming.is_zero() { + Ok(SwapIntoForeignDone { done_swap: swap }) + } else { + Ok(RedeemingAndSwapIntoForeignDone { + redeem_amount: amount_redeeming, + done_swap: swap, + }) + } + } + _ => Err(DispatchError::Other( + "Invalid pre redeem state when transitioning non-foreign collect", + )), + } + } + /// Apply the transition of the state after collecting a redemption: - /// * If the collected amount (in pool currency) is positive, this indicates - /// that we need to initiate the swap into foreign currency - /// * If the collected amount is zero, this indicates that the collection is - /// considered to be done. + /// * Either remove or update the redeeming amount + /// * Either add or update an active swap into foreign currency (or note a + /// fulfilled swap if the in and out currencies are the same). /// - /// Throws if + /// Throws if any of the following holds true /// * The current state includes an active/done swap and in and out - /// currencies do not match the provided ones; or - /// * The collected amount is zero but the state does not include a foreign - /// `ActiveSwapIntoForeignCurrency` or `SwapIntoForeignDone` + /// currencies do not match the provided ones + /// * The collected amount is zero but there is a mismatch between the + /// redeeming amounts (which can only be possible if something was + /// collected) + /// * The state does not include `Redeeming` fn transition_collect( &self, + amount_redeeming: Balance, collected_swap: Swap, ) -> Result { + let redeeming_amount = self.get_redeeming_amount(); + ensure!( self.get_active_swap() .map(|swap| (swap.currency_in, swap.currency_out) @@ -599,185 +602,93 @@ where DispatchError::Other("Invalid swap currencies when transitioning collect redemption") ); + // Nothing changed in the executed epoch + if collected_swap.amount.is_zero() { + if redeeming_amount == amount_redeeming { + return Ok(*self); + } else { + return Err(DispatchError::Other( + "Corruption: Redeeming amount changed but nothing was collected", + )); + } + } + + // Take shortcut for same currencies if collected_swap.currency_in == collected_swap.currency_out { - return Self::transition_collect_non_foreign(self, collected_swap); + return Self::transition_collect_non_foreign(self, amount_redeeming, collected_swap); } - // A collectable redemption is considered to be _done_ iff the amount of pool - // currency returned after calling `collect_redeem` is zero + // Either remove or update redeeming amount and add/update swap into foreign + // currency match *self { - CollectableRedemption => { - if collected_swap.amount.is_zero() { - Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) - } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { + Redeeming { .. } => { + if amount_redeeming.is_zero() { + Ok(Self::ActiveSwapIntoForeignCurrency { swap: collected_swap, }) - } - }, - RedeemingAndCollectableRedemption { redeem_amount } => { - if collected_swap.amount.is_zero() { - Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include swap")) } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { - redeem_amount, - swap: collected_swap, - }) - } - }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { - if collected_swap.amount.is_zero() { Ok(Self::RedeemingAndActiveSwapIntoForeignCurrency { - redeem_amount, - swap - }) - } - else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { - redeem_amount, - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - } - }) - } - }, - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, done_swap } => { - if collected_swap.amount.is_zero() { - Ok(Self::RedeemingAndSwapIntoForeignDone { - redeem_amount, - done_swap, - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - redeem_amount, - swap: Swap { - amount: collected_swap.amount, - ..collected_swap - }, - done_amount: done_swap.amount - }) - } - }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { - if collected_swap.amount.is_zero() { - Ok(Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - redeem_amount, - swap, - done_amount - }) - } else { - Ok(Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - redeem_amount, - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - done_amount + redeem_amount: amount_redeeming, + swap: collected_swap, }) } - }, - CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { - if collected_swap.amount.is_zero() { - Ok(Self::ActiveSwapIntoForeignCurrency { - swap, - }) + } + RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { + let new_swap = Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + if amount_redeeming.is_zero() { + Ok(Self::ActiveSwapIntoForeignCurrency { swap: new_swap }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, + Ok(Self::RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount: amount_redeeming, + swap: new_swap, }) } - }, - CollectableRedemptionAndSwapIntoForeignDone { done_swap } => { - if collected_swap.amount.is_zero() { - Ok(Self::SwapIntoForeignDone { - done_swap, + } + RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + if amount_redeeming.is_zero() { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: collected_swap, + done_amount: done_swap.amount, }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: collected_swap.amount, - ..collected_swap + Ok( + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount: amount_redeeming, + swap: collected_swap, + done_amount: done_swap.amount, }, - done_amount: done_swap.amount, - }) + ) } - }, - CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { - if collected_swap.amount.is_zero() { + } + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + .. + } => { + let new_swap = Swap { + amount: swap.amount.ensure_add(collected_swap.amount)?, + ..collected_swap + }; + if amount_redeeming.is_zero() { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap, - done_amount + swap: new_swap, + done_amount, }) } else { - Ok(Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap + Ok( + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount: amount_redeeming, + swap: new_swap, + done_amount, }, - done_amount - }) - } - }, - state => Ok(state) - } - } - - /// Apply the transition of the state after collecting a redemption in - /// non-foreign currencies. - /// * Ignores any states without `CollectableRedemption`. - /// * Throws for all states with `CollectableRedemption` and - /// `ActiveSwapIntoForeignCurrency` as there can't be an active swap for - /// non-foreign currencies, these should immediately fulfilled. - /// * Else replaces `CollectableRedemption` with `SwapIntoForeignDone` if - /// it did not exist already. If it did, increment the done swap amount - /// by the collected one. - fn transition_collect_non_foreign( - &self, - collected_swap: Swap, - ) -> Result { - match *self { - CollectableRedemption => { - if collected_swap.amount.is_zero() { - Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) - } else { - Ok(Self::CollectableRedemptionAndSwapIntoForeignDone { - done_swap: collected_swap, - }) - } - } - RedeemingAndCollectableRedemption { redeem_amount } => { - if collected_swap.amount.is_zero() { - Err(DispatchError::Other("Cannot clear CollectableRedemption if the collected amount is zero and state does not include done swap")) - } else { - Ok(Self::RedeemingAndSwapIntoForeignDone { - redeem_amount, - done_swap: collected_swap, - }) + ) } } - - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - redeem_amount, - done_swap, - } => Ok(RedeemingAndSwapIntoForeignDone { - redeem_amount, - done_swap: Swap { - amount: done_swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - }), - CollectableRedemptionAndSwapIntoForeignDone { done_swap } => Ok(SwapIntoForeignDone { - done_swap: Swap { - amount: done_swap.amount.ensure_add(collected_swap.amount)?, - ..collected_swap - }, - }), _ => Err(DispatchError::Other( - "Invalid pre state when transitioning collect for same currencies", + "Invalid pre redeem state when transitioning foreign collect", )), } } @@ -821,12 +732,12 @@ where } => { if &amount == invest_amount { Ok(Self::NotInvestedAnd { - inner: inner.add_or_overwrite_redeem_amount(amount)?, + inner: inner.set_redeem_amount(amount)?, }) } else { Ok(Self::InvestedAnd { invest_amount: invest_amount.ensure_sub(amount)?, - inner: inner.add_or_overwrite_redeem_amount(amount)?, + inner: inner.set_redeem_amount(amount)?, }) } } @@ -864,7 +775,7 @@ where }), _ => Ok(Self::InvestedAnd { invest_amount: amount, - inner: inner.add_or_overwrite_redeem_amount(Balance::zero())?, + inner: inner.set_redeem_amount(Balance::zero())?, }), }, Self::InvestedAnd { @@ -876,7 +787,7 @@ where Redeeming { .. } => Ok(Self::Invested { invest_amount }), _ => Ok(Self::InvestedAnd { invest_amount, - inner: inner.add_or_overwrite_redeem_amount(Balance::zero())?, + inner: inner.set_redeem_amount(Balance::zero())?, }), } } @@ -890,7 +801,7 @@ where Self::NoState | Self::Invested { .. } => error_not_redeeming, Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { invest_amount: amount, - inner: inner.add_or_overwrite_redeem_amount(redeem_amount)?, + inner: inner.set_redeem_amount(redeem_amount)?, }), Self::InvestedAnd { invest_amount, @@ -899,7 +810,7 @@ where let invest_amount = invest_amount.ensure_add(amount)?; Ok(Self::InvestedAnd { invest_amount, - inner: inner.add_or_overwrite_redeem_amount(redeem_amount)?, + inner: inner.set_redeem_amount(redeem_amount)?, }) } } @@ -913,36 +824,27 @@ where swap: Swap, ) -> Result { match self { - Self::NotInvestedAnd { inner } => Ok(Self::NotInvestedAnd { - inner: inner.transition_fulfilled_swap_order(swap)?, - }), - Self::InvestedAnd { - invest_amount, - inner, - } => Ok(Self::InvestedAnd { - invest_amount: *invest_amount, - inner: inner.transition_fulfilled_swap_order(swap)?, - }), + Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => Ok( + Self::swap_inner_state(self, inner.transition_fulfilled_swap_order(swap)?), + ), _ => Err(DispatchError::Other( "Invalid redeem state when transitioning a fulfilled order", )), } } - /// Remove `CollectableRedemption` from all inner states which include it. - /// Either swap it with `ActiveSwapIntoForeignCurrency` if the inner state - /// did not include an active swap or simply drop it. - /// - /// Throws if the state does not allow for collection or the the inner state - /// includes an active/done swap with mismatching currencies to the provided - /// ones. - fn handle_collect(&self, swap: Swap) -> Result { + /// Update the inner state if it includes `Redeeming`. + fn handle_collect( + &self, + amount_redeeming: Balance, + swap: Swap, + ) -> Result { match self { RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( "Invalid redeem state when transitioning collect", )), RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( - Self::swap_inner_state(self, inner.transition_collect(swap)?), + Self::swap_inner_state(self, inner.transition_collect(amount_redeeming, swap)?), ), } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index bb4df0bd5f..7072ddd787 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -41,7 +41,6 @@ pub mod pallet { }; use errors::{InvestError, RedeemError}; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; - use frame_system::pallet_prelude::*; use sp_runtime::traits::AtLeast32BitUnsigned; use types::{InvestState, RedeemState}; @@ -202,20 +201,22 @@ pub mod pallet { /// investment after the potential swap. In case a swap is not required, the /// investment starts with `InvestState::InvestmentOngoing`. #[pallet::storage] - pub(super) type InvestmentState = StorageDoubleMap< + pub type InvestmentState = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, InvestState, + ValueQuery, >; /// Maps an investor and their `InvestmentId` to the corresponding /// `RedeemState`. /// /// NOTE: The lifetime of this storage starts with increasing a redemption - /// if there exists a processed investment. It ends with transferring back + /// which requires owning at least the amount of tranche tokens by which the + /// redemption shall be increased by. It ends with transferring back /// the swapped return currency to the corresponding source domain from /// which the investment originated. The lifecycle must go through the /// following stages: @@ -226,13 +227,14 @@ pub mod pallet { /// 5. Completely fulfill swap order /// 6. Transfer back to source domain --> Kill storage entry #[pallet::storage] - pub(super) type RedemptionState = StorageDoubleMap< + pub type RedemptionState = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, RedeemState, + ValueQuery, >; /// Maps `TokenSwapOrders` to `ForeignInvestmentInfo` to implicitly enable @@ -269,7 +271,7 @@ pub mod pallet { /// in pool currency and ends with having swapped the entire amount to /// return currency which is assumed to be asynchronous. #[pallet::storage] - pub(super) type CollectedRedemptionTrancheTokens = StorageDoubleMap< + pub type CollectedRedemptionTrancheTokens = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, @@ -303,7 +305,6 @@ pub mod pallet { } #[pallet::error] - // TODO: Add more errors pub enum Error { InvalidInvestmentCurrency, /// Failed to retrieve the `TokenSwapReason` from the given @@ -329,76 +330,4 @@ pub mod pallet { Error::::RedeemError(error) } } - - #[pallet::call] - impl Pallet { - /// Attempts to transition an `InvestState` after an epoch execution: - /// * If the state includes `InvestmentOngoing` and the unprocessed - /// investment amount is zero, removes `InvestmentOngoing`. - /// * If the state includes `InvestmentOngoing` and the unprocessed - /// investment amount is positive, updates the `invest_amount` to the - /// unprocessed one. - /// - /// NOOP: If the unprocessed investment amount is zero or the state does - /// not include `InvestmentOngoing` - #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] - #[pallet::call_index(1)] - pub fn nudge_invest_state( - origin: OriginFor, - investor: T::AccountId, - investment_id: T::InvestmentId, - ) -> DispatchResult { - ensure_signed(origin)?; - - if let Some(invest_state) = InvestmentState::::get(&investor, investment_id) { - let amount_unprocessed_investment = - T::Investment::investment(&investor, investment_id)?; - let new_state = invest_state - .transition(types::InvestTransition::EpochExecution( - amount_unprocessed_investment, - )) - .map_err(|e| { - log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::EpochExecution) - })?; - Pallet::::apply_invest_state_transition(&investor, investment_id, new_state)?; - } - Ok(()) - } - - /// Attempts to transition a `RedeemState` after an epoch execution: - /// * If the inner state includes `Redeeming` and the unprocessed - /// redemption amount is zero, removes `Redeeming`. - /// * If the inner state includes `Redeeming` and the unprocessed - /// redemption amount is positive, updates the amount to the - /// unprocessed one. - /// - /// NOOP: If the unprocessed redemption amount is zero or the inner - /// state does not include `Redeeming`. - #[pallet::weight(100_000_000 + T::DbWeight::get().reads_writes(5, 5).ref_time())] - #[pallet::call_index(2)] - pub fn nudge_redeem_state( - origin: OriginFor, - investor: T::AccountId, - investment_id: T::InvestmentId, - ) -> DispatchResult { - ensure_signed(origin)?; - - if let Some(redeem_state) = RedemptionState::::get(&investor, investment_id) { - let amount_unprocessed_redemption = - T::Investment::redemption(&investor, investment_id)?; - let new_state = redeem_state - .transition(types::RedeemTransition::EpochExecution( - amount_unprocessed_redemption, - )) - .map_err(|e| { - log::debug!("RedeemState transition error: {:?}", e); - Error::::from(RedeemError::EpochExecution) - })?; - Pallet::::apply_redeem_state_transition(&investor, investment_id, new_state)?; - } - - Ok(()) - } - } } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index a9e9b25d00..b45d685da4 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -158,7 +158,7 @@ pub enum InvestTransition< /// * If the previous state includes `ActiveSwapIntoForeignCurrency`, /// `currency_in` is the foreign currency. FulfillSwapOrder(Swap), - EpochExecution(Balance), + CollectInvestment(Balance), } /// Reflects all states a foreign redemption can have until transferred to the @@ -326,6 +326,5 @@ pub enum RedeemTransition< IncreaseRedeemOrder(Balance), DecreaseRedeemOrder(Balance), FulfillSwapOrder(Swap), - Collect(Swap), - EpochExecution(Balance), + CollectRedemption(Balance, Swap), } diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 4f9d767866..52e07307ed 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -671,7 +671,7 @@ where return Ok((Default::default(), ().into())); } - let mut amount_payment: T::Amount = Default::default(); + let mut amount_payment = T::Amount::zero(); for order_id in order.submitted_at()..last_processed_order_id { let fulfillment = ClearedInvestOrders::::try_get(investment_id, order_id) .map_err(|_| Error::::OrderNotCleared)?; @@ -777,7 +777,7 @@ where return Ok((Default::default(), ().into())); } - let mut amount_payment: T::Amount = Default::default(); + let mut amount_payment = T::Amount::zero(); for order_id in order.submitted_at()..last_processed_order_id { let fulfillment = ClearedRedeemOrders::::try_get(investment_id, order_id) .map_err(|_| Error::::OrderNotCleared)?; diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 1650356922..371387a5fc 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -63,6 +63,7 @@ where currency_payout: status.amount_decreased, }; + // TODO: Collect payment from treasury instead T::OutboundQueue::submit(investor, domain_address.domain(), message)?; Ok(()) @@ -102,6 +103,7 @@ where tranche_tokens_payout: status.amount_tranche_tokens_payout, }; + // TODO: Collect payment from treasury instead T::OutboundQueue::submit(investor, domain_address.domain(), message)?; Ok(()) diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 26e5bf360a..3e1d75c9eb 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -246,6 +246,7 @@ where tranche_tokens_payout, }; + // TODO: Collect fee from treasury instead T::OutboundQueue::submit(investor, destination.domain(), message)?; Ok(()) @@ -326,6 +327,7 @@ where tranche_tokens_payout: amount_tranche_tokens_payout, }; + // TODO: Collect fee from treasury instead T::OutboundQueue::submit(investor, destination.domain(), message)?; Ok(()) diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index c23445bb42..46720476c3 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1794,7 +1794,7 @@ construct_runtime!( LiquidityPools: pallet_liquidity_pools::{Pallet, Call, Storage, Event} = 108, LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 109, OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 110, - ForeignInvestments: pallet_foreign_investments::{Pallet, Call, Storage, Event} = 111, + ForeignInvestments: pallet_foreign_investments::{Pallet, Storage, Event} = 111, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 7f559ef487..8c1846e4b6 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1957,7 +1957,7 @@ construct_runtime!( GapRewardMechanism: pallet_rewards::mechanism::gap = 114, LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 115, OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 116, - ForeignInvestments: pallet_foreign_investments::{Pallet, Call, Storage, Event} = 117, + ForeignInvestments: pallet_foreign_investments::{Pallet, Storage, Event} = 117, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index 8cfc8c36b1..6165eb8253 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -97,6 +97,7 @@ liquidity-pools-gateway-routers = { path = "../../pallets/liquidity-pools-gatewa pallet-block-rewards = { path = "../../pallets/block-rewards" } pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction" } pallet-investments = { path = "../../pallets/investments" } +pallet-foreign-investments = { path = "../../pallets/foreign-investments" } pallet-liquidity-pools = { path = "../../pallets/liquidity-pools" } pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway" } pallet-loans = { path = "../../pallets/loans" } @@ -136,6 +137,7 @@ std = [ "orml-xtokens/std", "pallet-aura/std", "pallet-balances/std", + "pallet-foreign-investments/std", "pallet-investments/std", "pallet-transaction-payment/std", "pallet-uniques/std", @@ -182,6 +184,7 @@ runtime-benchmarks = [ "orml-tokens/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-foreign-investments/runtime-benchmarks", "pallet-investments/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 5089eedefe..4f524d39d1 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -48,9 +48,9 @@ use cfg_types::{ }; use codec::Encode; use development_runtime::{ - Balances, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, OrmlAssetRegistry, - OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, System, - XTokens, XcmTransactor, + Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, + OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, XTokens, XcmTransactor, }; use frame_support::{ assert_noop, assert_ok, @@ -60,6 +60,7 @@ use frame_support::{ use hex::FromHex; use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; use pallet_investments::CollectOutcome; use pallet_liquidity_pools::{ encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, @@ -388,27 +389,14 @@ fn transfer_non_tranche_tokens_from_local() { ); // Enable LiquidityPools transferability - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), + utils::enable_liquidity_pool_transferability( currency_id, - None, - None, - None, - None, - // Changed: Add location which can be converted to LiquidityPoolsWrappedToken Some(Some(utils::liquidity_pools_transferable_multilocation( MOONBEAM_EVM_CHAIN_ID, // Value of evm_address is irrelevant here [1u8; 20], ))), - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - mintable: Default::default(), - permissioned: Default::default(), - pool_currency: Default::default() - }) - )); + ); // Cannot transfer more than owned assert_noop!( @@ -468,18 +456,6 @@ fn transfer_non_tranche_tokens_to_local() { assert!(OrmlTokens::total_issuance(currency_id).is_zero()); - // TODO(after PR #1376): Re-activate via Gateway handling - // // Verify that we do not accept incoming messages if the connection has not - // been // initialized - // assert_noop!( - // LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - // pallet_liquidity_pools::Error::::InvalidIncomingMessageOrigin - // ); - // assert_ok!(LiquidityPools::add_instance( - // RuntimeOrigin::root(), - // utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.address().into() - // )); - // Finally, verify that we can now transfer the tranche to the destination // address assert_ok!(LiquidityPools::submit( @@ -636,18 +612,6 @@ fn transfer_tranche_tokens_to_local() { amount, }; - // TODO(after PR #1376): Re-activate via Gateway handling - // // Verify that we do not accept incoming messages if the connection has not - // been // initialized - // assert_noop!( - // LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - // pallet_liquidity_pools::Error::::InvalidIncomingMessageOrigin - // ); - // assert_ok!(LiquidityPools::add_instance( - // RuntimeOrigin::root(), - // utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.address().into() - // )); - // Verify that we first need the receiver to be whitelisted assert_noop!( LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), @@ -686,13 +650,6 @@ fn transfer_tranche_tokens_to_local() { // to the dest domain account on Centrifuge. assert_eq!(OrmlTokens::free_balance(tranche_tokens, &receiver), amount); assert!(OrmlTokens::free_balance(tranche_tokens, &sending_domain_locator).is_zero()); - - // TODO(subsequent PR): Verify that we cannot transfer to the local - // domain blocked by https://github.com/centrifuge/centrifuge-chain/pull/1376 - // assert_noop!( - // LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), - // pallet_liquidity_pools::Error::::InvalidDomain - // ); }); } @@ -782,29 +739,16 @@ fn add_currency() { utils::setup_pre_requirements(); let currency_id = AUSD_CURRENCY_ID; - let location = utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - utils::DEFAULT_EVM_ADDRESS_MOONBEAM, - ); // Enable LiquidityPools transferability - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), + utils::enable_liquidity_pool_transferability( currency_id, - None, - None, - None, - None, - // Changed: Add location which can be converted to LiquidityPoolsWrappedToken - Some(Some(location)), - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - mintable: Default::default(), - permissioned: Default::default(), - pool_currency: Default::default() - }) - )); + Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))), + ); assert_ok!(LiquidityPools::add_currency( RuntimeOrigin::signed(BOB.into()), @@ -914,35 +858,6 @@ fn add_currency_should_fail() { LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - - // TODO(subsequent PR): Reactivate later - // Blocked by https://github.com/centrifuge/centrifuge-chain/pull/1376 - - // // Should fail if no domain router is registered for the asset's - // // metadata evm chain id - // assert_ok!(OrmlAssetRegistry::update_asset( - // RuntimeOrigin::root(), - // currency_id, - // None, - // None, - // None, - // None, - // None, - // Some(CustomMetadata { - // // Changed: Enable all cross chain transferability in metadata - // transferability: CrossChainTransferability::All(XcmMetadata { - // fee_per_second: Default::default() - // }), - // mintable: Default::default(), - // permissioned: Default::default(), - // pool_currency: Default::default(), - // }) - // )); - // assert_noop!( - // LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), - // currency_id), - // pallet_liquidity_pools::Error::::MissingRouter - // ); }); } @@ -1153,481 +1068,583 @@ fn allow_pool_should_fail() { }); } -#[test] -fn inbound_increase_invest_order() { - TestNet::reset(); +mod non_foreign_currencies { + use super::*; - Development::execute_with(|| { - utils::setup_pre_requirements(); + #[test] + fn inbound_increase_invest_order() { + TestNet::reset(); - let pool_id = 42; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + Development::execute_with(|| { + utils::setup_pre_requirements(); - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + let pool_id = 42; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment(pool_id, amount, investor, currency_id); + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Verify the order was updated to the amount - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) - ) - .amount, - amount - ); - }); -} - -#[test] -fn inbound_decrease_invest_order_same_currencies() { - TestNet::reset(); + // Set permissions and execute initial investment + utils::investments::do_initial_increase_investment( + pool_id, + amount, + investor, + currency_id, + ); - Development::execute_with(|| { - utils::setup_pre_requirements(); + // Verify the order was updated to the amount + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + amount + ); + }); + } - let pool_id = 42; - let invest_amount = 100_000_000; - let decrease_amount = invest_amount / 3; - let final_amount = invest_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + #[test] + fn inbound_decrease_invest_order() { + TestNet::reset(); - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + Development::execute_with(|| { + utils::setup_pre_requirements(); - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); + let pool_id = 42; + let invest_amount = 100_000_000; + let decrease_amount = invest_amount / 3; + let final_amount = invest_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + // Set permissions and execute initial investment + utils::investments::do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Mock incoming decrease message + let msg = utils::LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), - final_amount - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + utils::enable_liquidity_pool_transferability( currency_id, - who: investor.clone(), - amount: decrease_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) - ) - .amount, - final_amount - ); - }); -} + Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))), + ); -#[test] -fn inbound_collect_invest_order() { - TestNet::reset(); + // Execute byte message + assert_ok!(LiquidityPools::submit( + utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - Development::execute_with(|| { - utils::setup_pre_requirements(); + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + currency_id, + &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + ), + final_amount + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + final_amount + ); + }); + } - let pool_id = 42; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + #[test] + fn inbound_collect_invest_order() { + TestNet::reset(); - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + Development::execute_with(|| { + utils::setup_pre_requirements(); - let investment_currency_id: CurrencyId = - investment_id(pool_id, default_tranche_id(pool_id)).into(); + let pool_id = 42; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = System::events(); + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_invest_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); - - // Tranche tokens will be minted upon fulfillment - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); - assert_ok!(Investments::invest_fulfillment( - investment_id(pool_id, default_tranche_id(pool_id)), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); + let investment_currency_id: CurrencyId = + investment_id(pool_id, default_tranche_id(pool_id)).into(); - // Mock collection message msg - let msg = utils::LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Set permissions and execute initial investment + utils::investments::do_initial_increase_investment( + pool_id, + amount, + investor.clone(), + currency_id, + ); + let events_before_collect = System::events(); - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::InvestCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_invest_orders(investment_id( + pool_id, + default_tranche_id(pool_id) + ))); - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); + // Tranche tokens will be minted upon fulfillment + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); + assert_ok!(Investments::invest_fulfillment( + investment_id(pool_id, default_tranche_id(pool_id)), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); - // Verify investment was collected into investor - assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investor - ), - amount - ); + // Mock collection message msg + let msg = utils::LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - who: investor.clone(), - } - .into() - })); + // Execute byte message + assert_ok!(LiquidityPools::submit( + utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify investment was transferred to the domain locator + assert_eq!( + OrmlTokens::free_balance( + investment_id(pool_id, default_tranche_id(pool_id)).into(), + &sending_domain_locator + ), + amount + ); + + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - submitted_at: 0, who: investor.clone(), - amount: 0, } .into() - })); + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { + // Foreign InvestmentState should be killed + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key( + investor.clone(), + investment_id(pool_id, default_tranche_id(pool_id)) + )); + + // Clearing of foreign InvestState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, } .into() - })); - }); -} + })); + }); + } -#[test] -fn inbound_increase_redeem_order() { - TestNet::reset(); + #[test] + fn inbound_increase_redeem_order() { + TestNet::reset(); - Development::execute_with(|| { - utils::setup_pre_requirements(); + Development::execute_with(|| { + utils::setup_pre_requirements(); - let pool_id = 42; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + let pool_id = 42; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Set permissions and execute initial redemption - utils::investments::do_initial_increase_redemption(pool_id, amount, investor, currency_id); - - // Verify amount was noted in the corresponding order - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)) - ) - .amount, - amount - ); - }); -} + // Set permissions and execute initial redemption + utils::investments::do_initial_increase_redemption( + pool_id, + amount, + investor, + currency_id, + ); -#[test] -fn inbound_decrease_redeem_order() { - TestNet::reset(); + // Verify amount was noted in the corresponding order + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + amount + ); + }); + } - Development::execute_with(|| { - utils::setup_pre_requirements(); + #[test] + fn inbound_decrease_redeem_order() { + TestNet::reset(); - let pool_id = 42; - let redeem_amount = 100_000_000; - let decrease_amount = redeem_amount / 3; - let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + Development::execute_with(|| { + utils::setup_pre_requirements(); - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + let pool_id = 42; + let redeem_amount = 100_000_000; + let decrease_amount = redeem_amount / 3; + let final_amount = redeem_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = + Domain::convert(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - // Set permissions and execute initial redemption - utils::investments::do_initial_increase_redemption( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( + // Set permissions and execute initial redemption + utils::investments::do_initial_increase_redemption( pool_id, - default_tranche_id(pool_id) - )), - 0 - ); + redeem_amount, + investor.clone(), + currency_id, + ); - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Mock incoming decrease message + let msg = utils::LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), - final_amount - ); - // Burning does not happen right away, so should still be in investor's wallet - assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investor - ), - decrease_amount - ); + // Execute byte message + assert_ok!(LiquidityPools::submit( + utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)), - ) - .amount, - final_amount - ); - }); -} + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + investment_id(pool_id, default_tranche_id(pool_id)).into(), + &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + ), + final_amount + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance( + investment_id(pool_id, default_tranche_id(pool_id)).into(), + &investor + ), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance( + investment_id(pool_id, default_tranche_id(pool_id)).into(), + &sending_domain_locator + ), + decrease_amount + ); -#[test] -fn inbound_collect_redeem_order() { - TestNet::reset(); + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + state: RedeemState::InvestedAnd { + invest_amount: decrease_amount, + inner: InnerRedeemState::Redeeming { + redeem_amount: final_amount + } + } + } + .into() + })); - Development::execute_with(|| { - utils::setup_pre_requirements(); + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + investment_id(pool_id, default_tranche_id(pool_id)), + ) + .amount, + final_amount + ); + }); + } - let pool_id = 42; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + #[test] + fn inbound_collect_redeem_order() { + TestNet::reset(); - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + Development::execute_with(|| { + utils::setup_pre_requirements(); - // Set permissions and execute initial investment - utils::investments::do_initial_increase_redemption( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = System::events(); + let pool_id = 42; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_redeem_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); - assert_ok!(Investments::redeem_fulfillment( - investment_id(pool_id, default_tranche_id(pool_id)), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); + // Set permissions and execute initial investment + utils::investments::do_initial_increase_redemption( + pool_id, + amount, + investor.clone(), + currency_id, + ); + let events_before_collect = System::events(); - // Mock collection message msg - let msg = utils::LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::RedeemCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_redeem_orders(investment_id( + pool_id, + default_tranche_id(pool_id) + ))); + assert_ok!(Investments::redeem_fulfillment( + investment_id(pool_id, default_tranche_id(pool_id)), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); + // Enable liquidity pool transferability + utils::enable_liquidity_pool_transferability( + currency_id, + Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))), + ); - // Verify investment was collected into investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), amount); + // Mock collection message msg + let msg = utils::LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)) - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - who: investor.clone(), - } - .into() - })); + // Execute byte message + assert_ok!(LiquidityPools::submit( + utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - submitted_at: 0, + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify collected redemption was burned from investor + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, who: investor.clone(), - amount: 0, + amount } - .into() - })); + .into())); - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), - processed_orders: vec![0], who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: amount, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, } .into() - })); - }); + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: amount, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign CollectedRedemptionTrancheTokens should be killed + assert!(!pallet_foreign_investments::CollectedRedemptionTrancheTokens::::contains_key( + investor.clone(), + investment_id(pool_id, default_tranche_id(pool_id)) + )); + + // Foreign RedemptionState should be killed + assert!(!pallet_foreign_investments::RedemptionState::< + DevelopmentRuntime, + >::contains_key( + investor.clone(), + investment_id(pool_id, default_tranche_id(pool_id)) + )); + + // Clearing of foreign RedeemState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionCleared { + investor: investor.clone(), + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + } + .into() + })); + }); + } } #[test] @@ -1688,6 +1705,7 @@ mod utils { parents: 1, interior: X1(Parachain(PARA_ID_MOONBEAM)), }; + pub type LiquidityPoolMessage = Message; pub fn get_default_moonbeam_native_token_location() -> MultiLocation { @@ -1976,16 +1994,6 @@ mod utils { currency: general_currency_index(currency_id), amount, }; - // TODO(after PR #1376): Re-activate via Gateway handling - // // Should fail if instance has not been added yet - // assert_noop!( - // LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - // pallet_liquidity_pools::Error::::InvalidIncomingMessageOrigin - // ); - // assert_ok!(LiquidityPools::add_instance( - // RuntimeOrigin::root(), - // utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.address().into() - // )); // Should fail if investor does not have investor role yet assert_noop!( @@ -2027,6 +2035,16 @@ mod utils { ), final_amount ); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { + investor: investor.clone(), + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + state: InvestState::InvestmentOngoing { + invest_amount: final_amount + }, + } + .into() + })); assert_eq!( System::events().iter().last().unwrap().event, pallet_investments::Event::::InvestOrderUpdated { @@ -2045,7 +2063,9 @@ mod utils { /// /// Assumes `utils::setup_pre_requirements` and /// `utils::investments::create_currency_pool` to have been called - /// beforehand + /// beforehand. + /// + /// NOTE: Mints exactly the redeeming amount of tranche tokens. pub fn do_initial_increase_redemption( pool_id: u64, amount: Balance, @@ -2086,16 +2106,6 @@ mod utils { currency: general_currency_index(currency_id), amount, }; - // TODO(after PR #1376): Re-activate via Gateway handling - // // Should fail if instance has not been added yet - // assert_noop!( - // LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - // pallet_liquidity_pools::Error::::InvalidIncomingMessageOrigin - // ); - // assert_ok!(LiquidityPools::add_instance( - // RuntimeOrigin::root(), - // utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.address().into() - // )); // Should fail if investor does not have investor role yet assert_noop!( @@ -2142,12 +2152,25 @@ mod utils { ), 0 ); + assert_eq!( + System::events().iter().nth_back(4).unwrap().event, + pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + state: RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: amount + } + }, + } + .into() + ); assert_eq!( System::events().iter().last().unwrap().event, pallet_investments::Event::::RedeemOrderUpdated { investment_id: investment_id(pool_id, default_tranche_id(pool_id)), submitted_at: 0, - who: investor, + who: investor.clone(), amount } .into() From ec7259d7dd82f1b578d94e5f6fb140b9490bf67d Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 22 Aug 2023 16:09:37 +0200 Subject: [PATCH 47/96] fix: treasury should pay Executed* msg tx fees --- pallets/liquidity-pools/src/hooks.rs | 11 +++++------ pallets/liquidity-pools/src/inbound.rs | 11 +++++------ pallets/liquidity-pools/src/lib.rs | 8 ++++++++ runtime/altair/src/lib.rs | 1 + runtime/development/src/lib.rs | 1 + 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 371387a5fc..0cc20c2022 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -19,6 +19,7 @@ use cfg_types::{ investments::{ExecutedForeignDecrease, ForeignInvestmentInfo}, }; use frame_support::{traits::fungibles::Mutate, transactional}; +use sp_core::Get; use sp_runtime::{DispatchError, DispatchResult}; use sp_std::marker::PhantomData; @@ -58,13 +59,12 @@ where let message: MessageOf = Message::ExecutedDecreaseInvestOrder { pool_id: investment_id.of_pool(), tranche_id: investment_id.of_tranche(), - investor: investor.clone().into(), + investor: investor.into(), currency, currency_payout: status.amount_decreased, }; - // TODO: Collect payment from treasury instead - T::OutboundQueue::submit(investor, domain_address.domain(), message)?; + T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; Ok(()) } @@ -97,14 +97,13 @@ where let message: MessageOf = Message::ExecutedCollectInvest { pool_id: investment_id.of_pool(), tranche_id: investment_id.of_tranche(), - investor: investor.clone().into(), + investor: investor.into(), currency, currency_payout: status.amount_currency_payout, tranche_tokens_payout: status.amount_tranche_tokens_payout, }; - // TODO: Collect payment from treasury instead - T::OutboundQueue::submit(investor, domain_address.domain(), message)?; + T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; Ok(()) } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 3e1d75c9eb..c0b60b92e6 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -23,6 +23,7 @@ use frame_support::{ ensure, traits::fungibles::{Mutate, Transfer}, }; +use sp_core::Get; use sp_runtime::{ traits::{Convert, Zero}, DispatchResult, @@ -241,13 +242,12 @@ where let message: MessageOf = Message::ExecutedDecreaseRedeemOrder { pool_id, tranche_id, - investor: investor.clone().into(), + investor: investor.into(), currency: currency_index.index, tranche_tokens_payout, }; - // TODO: Collect fee from treasury instead - T::OutboundQueue::submit(investor, destination.domain(), message)?; + T::OutboundQueue::submit(T::TreasuryAccount::get(), destination.domain(), message)?; Ok(()) } @@ -321,14 +321,13 @@ where let message: MessageOf = Message::ExecutedCollectInvest { pool_id, tranche_id, - investor: investor.clone().into(), + investor: investor.into(), currency: currency_index_u128, currency_payout: amount_currency_payout, tranche_tokens_payout: amount_tranche_tokens_payout, }; - // TODO: Collect fee from treasury instead - T::OutboundQueue::submit(investor, destination.domain(), message)?; + T::OutboundQueue::submit(T::TreasuryAccount::get(), destination.domain(), message)?; Ok(()) } diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 25469de018..3a0866096c 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -235,6 +235,14 @@ pub mod pallet { /// The prefix for currencies added via the LiquidityPools feature. #[pallet::constant] type GeneralCurrencyPrefix: Get<[u8; 12]>; + + /// The type for paying the transaction fees for the dispatch of + /// `Executed*` messages. + /// + /// NOTE: We need to make sure to collect the appropriate amount + /// beforehand as part of receiving the corresponding investment + /// message. + type TreasuryAccount: Get<::AccountId>; } #[pallet::event] diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 46720476c3..754fb4699e 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1385,6 +1385,7 @@ impl pallet_liquidity_pools::Config for Runtime { type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; type TrancheTokenPrice = PoolSystem; + type TreasuryAccount = TreasuryAccount; type WeightInfo = (); } diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 8c1846e4b6..0b321211ec 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1619,6 +1619,7 @@ impl pallet_liquidity_pools::Config for Runtime { type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; type TrancheTokenPrice = PoolSystem; + type TreasuryAccount = TreasuryAccount; type WeightInfo = (); } From 94d314915f56171feacb2ab32921ec1e42e3ef86 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 23 Aug 2023 09:40:38 +0200 Subject: [PATCH 48/96] feat: add non-foreign cancel_invest_order --- .../development/tests/liquidity_pools.rs | 130 +++++++++++++++++- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 4f524d39d1..8125fe2234 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -27,7 +27,7 @@ use ::xcm::{ prelude::{Parachain, X1, X2}, VersionedMultiLocation, }; -use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId}; +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::{Codec, InboundQueue}, @@ -50,12 +50,12 @@ use codec::Encode; use development_runtime::{ Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, XTokens, XcmTransactor, + RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, }; use frame_support::{ assert_noop, assert_ok, dispatch::Weight, - traits::{fungibles::Mutate, Get, PalletInfo}, + traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, }; use hex::FromHex; use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; @@ -1198,6 +1198,119 @@ mod non_foreign_currencies { }); } + #[test] + fn inbound_cancel_invest_order() { + TestNet::reset(); + + Development::execute_with(|| { + utils::setup_pre_requirements(); + + let pool_id = 42; + let invest_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + utils::investments::do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); + + // Verify investment account holds funds before cancelling + assert_eq!( + OrmlTokens::free_balance( + currency_id, + &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + ), + invest_amount + ); + + // Mock incoming cancel message + let msg = utils::LiquidityPoolMessage::CancelInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + utils::enable_liquidity_pool_transferability( + currency_id, + Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))), + ); + + // Execute byte message + assert_ok!(LiquidityPools::submit( + utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg + )); + + // Foreign InvestmentState should be cleared + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key( + &investor, + investment_id(pool_id, default_tranche_id(pool_id)) + )); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + } + .into() + })); + + // Verify investment was entirely drained from investment account + assert_eq!( + OrmlTokens::free_balance( + currency_id, + &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + ), + 0 + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: invest_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + investment_id(pool_id, default_tranche_id(pool_id)) + ) + .amount, + 0 + ); + }); + } + #[test] fn inbound_collect_invest_order() { TestNet::reset(); @@ -1757,7 +1870,8 @@ mod utils { /// * transact info and domain router for Moonbeam `MultiLocation`, /// * fee for GLMR (`GLIMMER_CURRENCY_ID`), /// * Register GLMR and AUSD in `OrmlAssetRegistry`, - /// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice and Bob. + /// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice, Bob and the + /// Treasury. /// /// NOTE: AUSD is the default pool currency in `create_pool`. /// Neither AUSD nor GLMR are registered as a liquidityPools-transferable @@ -1787,9 +1901,15 @@ mod utils { Some(GLIMMER_CURRENCY_ID) )); - // Give Alice and BOB enough glimmer to pay for fees + // Give Alice, Bob and Treasury enough glimmer to pay for fees OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &ALICE.into(), DEFAULT_BALANCE_GLMR); OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &BOB.into(), DEFAULT_BALANCE_GLMR); + // Treasury pays for `Executed*` messages + OrmlTokens::deposit( + GLIMMER_CURRENCY_ID, + &TreasuryPalletId::get().into_account_truncating(), + DEFAULT_BALANCE_GLMR, + ); // Register AUSD in the asset registry which is the default pool currency in // `create_pool` From 7caecc1c08c69ea32e2cc4e17ef52e36d23735eb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 23 Aug 2023 09:40:57 +0200 Subject: [PATCH 49/96] refactor: remove liquidity pools clutter --- .../development/tests/liquidity_pools.rs | 295 ++++++------------ 1 file changed, 104 insertions(+), 191 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs index 8125fe2234..9e2f1f4787 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs @@ -77,9 +77,7 @@ use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, }; -use utils::investments::{ - default_tranche_id, general_currency_index, investment_account, investment_id, -}; +use utils::investments::{default_tranche_id, general_currency_index, investment_id}; use xcm_emulator::TestExt; use crate::{ @@ -88,7 +86,7 @@ use crate::{ test_net::{Development, Moonbeam, RelayChain, TestNet}, tests::liquidity_pools::utils::{ get_default_moonbeam_native_token_location, liquidity_pools_transferable_multilocation, - DEFAULT_MOONBEAM_LOCATION, + DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, }, }, utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, @@ -113,7 +111,7 @@ fn add_pool() { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; // Verify that the pool must exist before we can call LiquidityPools::add_pool assert_noop!( @@ -162,7 +160,7 @@ fn add_tranche() { let decimals: u8 = 15; // Now create the pool - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; utils::create_ausd_pool(pool_id); // Verify we can't call LiquidityPools::add_tranche with a non-existing @@ -177,13 +175,7 @@ fn add_tranche() { ), pallet_liquidity_pools::Error::::TrancheNotFound ); - - // Find the right tranche id - let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); - let tranche_id = pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists"); + let tranche_id = default_tranche_id(pool_id); // Verify ALICE can't call `add_tranche` given she is not the `PoolAdmin` assert_noop!( @@ -215,15 +207,9 @@ fn update_member() { utils::setup_pre_requirements(); // Now create the pool - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; utils::create_ausd_pool(pool_id); - - // Find the right tranche id - let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); - let tranche_id = pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists"); + let tranche_id = default_tranche_id(pool_id); // Finally, verify we can call LiquidityPools::add_tranche successfully // when given a valid pool + tranche id pair. @@ -303,21 +289,14 @@ fn update_token_price() { let decimals: u8 = 15; // Now create the pool - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; utils::create_ausd_pool(pool_id); - // Find the right tranche id - let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); - let tranche_id = pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists"); - // Verify it now works assert_ok!(LiquidityPools::update_token_price( RuntimeOrigin::signed(ALICE.into()), pool_id, - tranche_id, + default_tranche_id(pool_id), Domain::EVM(1284), )); }); @@ -389,14 +368,7 @@ fn transfer_non_tranche_tokens_from_local() { ); // Enable LiquidityPools transferability - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + utils::enable_liquidity_pool_transferability(currency_id); // Cannot transfer more than owned assert_noop!( @@ -490,7 +462,7 @@ fn transfer_tranche_tokens_from_local() { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; let amount = 100_000; let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); let receiver = BOB; @@ -581,7 +553,7 @@ fn transfer_tranche_tokens_to_local() { utils::setup_pre_requirements(); // Create new pool - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; utils::create_ausd_pool(pool_id); let amount = 100_000_000; @@ -665,11 +637,7 @@ fn transferring_invalid_tranche_tokens_should_fail() { let valid_pool_id: u64 = 42; utils::create_ausd_pool(valid_pool_id); - let pool_details = PoolSystem::pool(valid_pool_id).expect("Pool should exist"); - let valid_tranche_id = pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists"); + let valid_tranche_id = default_tranche_id(valid_pool_id); let valid_until = u64::MAX; let transfer_amount = 42; let invalid_pool_id = valid_pool_id + 1; @@ -741,14 +709,7 @@ fn add_currency() { let currency_id = AUSD_CURRENCY_ID; // Enable LiquidityPools transferability - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + utils::enable_liquidity_pool_transferability(currency_id); assert_ok!(LiquidityPools::add_currency( RuntimeOrigin::signed(BOB.into()), @@ -869,7 +830,7 @@ fn allow_pool_currency() { utils::setup_pre_requirements(); let currency_id = AUSD_CURRENCY_ID; - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; let evm_address = [1u8; 20]; @@ -912,7 +873,7 @@ fn allow_pool_should_fail() { TestNet::reset(); Development::execute_with(|| { - let pool_id: u64 = 42; + let pool_id = DEFAULT_POOL_ID; let currency_id = CurrencyId::ForeignAsset(42); let ausd_currency_id = AUSD_CURRENCY_ID; @@ -1070,6 +1031,9 @@ fn allow_pool_should_fail() { mod non_foreign_currencies { use super::*; + use crate::liquidity_pools::pallet::development::tests::liquidity_pools::utils::investments::{ + default_investment_account, default_investment_id, + }; #[test] fn inbound_increase_invest_order() { @@ -1078,7 +1042,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); let currency_id = AUSD_CURRENCY_ID; @@ -1098,7 +1062,7 @@ mod non_foreign_currencies { // Verify the order was updated to the amount assert_eq!( pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, amount @@ -1113,7 +1077,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; let decrease_amount = invest_amount / 3; let final_amount = invest_amount - decrease_amount; @@ -1147,14 +1111,7 @@ mod non_foreign_currencies { LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + utils::enable_liquidity_pool_transferability(currency_id); // Execute byte message assert_ok!(LiquidityPools::submit( @@ -1164,10 +1121,7 @@ mod non_foreign_currencies { // Verify investment was decreased into investment account assert_eq!( - OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), + OrmlTokens::free_balance(currency_id, &default_investment_account()), final_amount ); // Since the investment was done in the pool currency, the decrement happens @@ -1175,7 +1129,7 @@ mod non_foreign_currencies { assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::InvestOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount: final_amount @@ -1190,7 +1144,7 @@ mod non_foreign_currencies { .into())); assert_eq!( pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, final_amount @@ -1205,7 +1159,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; let investor: AccountId = BOB.into(); let currency_id = AUSD_CURRENCY_ID; @@ -1224,10 +1178,7 @@ mod non_foreign_currencies { // Verify investment account holds funds before cancelling assert_eq!( - OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), + OrmlTokens::free_balance(currency_id, &default_investment_account()), invest_amount ); @@ -1245,14 +1196,7 @@ mod non_foreign_currencies { LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + utils::enable_liquidity_pool_transferability(currency_id); // Execute byte message assert_ok!(LiquidityPools::submit( @@ -1263,24 +1207,18 @@ mod non_foreign_currencies { // Foreign InvestmentState should be cleared assert!(!pallet_foreign_investments::InvestmentState::< DevelopmentRuntime, - >::contains_key( - &investor, - investment_id(pool_id, default_tranche_id(pool_id)) - )); + >::contains_key(&investor, default_investment_id())); assert!(System::events().iter().any(|e| { e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), } .into() })); // Verify investment was entirely drained from investment account assert_eq!( - OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), + OrmlTokens::free_balance(currency_id, &default_investment_account()), 0 ); // Since the investment was done in the pool currency, the decrement happens @@ -1288,7 +1226,7 @@ mod non_foreign_currencies { assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::InvestOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount: 0 @@ -1303,7 +1241,7 @@ mod non_foreign_currencies { .into())); assert_eq!( pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, 0 @@ -1318,7 +1256,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); let currency_id = AUSD_CURRENCY_ID; @@ -1329,8 +1267,7 @@ mod non_foreign_currencies { // Create new pool utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - let investment_currency_id: CurrencyId = - investment_id(pool_id, default_tranche_id(pool_id)).into(); + let investment_currency_id: CurrencyId = default_investment_id().into(); // Set permissions and execute initial investment utils::investments::do_initial_increase_investment( @@ -1352,7 +1289,7 @@ mod non_foreign_currencies { // Tranche tokens will be minted upon fulfillment assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); assert_ok!(Investments::invest_fulfillment( - investment_id(pool_id, default_tranche_id(pool_id)), + default_investment_id(), FulfillmentWithPrice:: { of_amount: Perquintill::one(), price: Rate::one(), @@ -1382,17 +1319,14 @@ mod non_foreign_currencies { // Verify investment was transferred to the domain locator assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &sending_domain_locator - ), + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), amount ); // Order should have been cleared by fulfilling investment assert_eq!( pallet_investments::Pallet::::acc_active_invest_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, 0 @@ -1400,7 +1334,7 @@ mod non_foreign_currencies { assert!(!events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), who: investor.clone(), } .into() @@ -1410,7 +1344,7 @@ mod non_foreign_currencies { assert!(!events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::InvestOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount: 0, @@ -1422,7 +1356,7 @@ mod non_foreign_currencies { assert!(events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::InvestOrdersCollected { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), processed_orders: vec![0], who: investor.clone(), collection: InvestCollection:: { @@ -1437,17 +1371,14 @@ mod non_foreign_currencies { // Foreign InvestmentState should be killed assert!(!pallet_foreign_investments::InvestmentState::< DevelopmentRuntime, - >::contains_key( - investor.clone(), - investment_id(pool_id, default_tranche_id(pool_id)) - )); + >::contains_key(investor.clone(), default_investment_id())); // Clearing of foreign InvestState should be dispatched assert!(events_since_collect.iter().any(|e| { e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), } .into() })); @@ -1461,7 +1392,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); let currency_id = AUSD_CURRENCY_ID; @@ -1481,7 +1412,7 @@ mod non_foreign_currencies { // Verify amount was noted in the corresponding order assert_eq!( pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, amount @@ -1496,7 +1427,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; let decrease_amount = redeem_amount / 3; let final_amount = redeem_amount - decrease_amount; @@ -1544,27 +1475,21 @@ mod non_foreign_currencies { // Verify investment was decreased into investment account assert_eq!( OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + default_investment_id().into(), + &default_investment_account(), ), final_amount ); // Tokens should have been transferred from investor's wallet to domain's // sovereign account assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investor - ), + OrmlTokens::free_balance(default_investment_id().into(), &investor), 0 ); // Tokens should have been transferred from investor's wallet to domain's // sovereign account assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &sending_domain_locator - ), + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), decrease_amount ); @@ -1572,7 +1497,7 @@ mod non_foreign_currencies { e.event == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), state: RedeemState::InvestedAnd { invest_amount: decrease_amount, inner: InnerRedeemState::Redeeming { @@ -1586,7 +1511,7 @@ mod non_foreign_currencies { // Order should have been updated assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount: final_amount @@ -1594,7 +1519,7 @@ mod non_foreign_currencies { .into())); assert_eq!( pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)), + default_investment_id(), ) .amount, final_amount @@ -1609,7 +1534,7 @@ mod non_foreign_currencies { Development::execute_with(|| { utils::setup_pre_requirements(); - let pool_id = 42; + let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); let currency_id = AUSD_CURRENCY_ID; @@ -1641,7 +1566,7 @@ mod non_foreign_currencies { default_tranche_id(pool_id) ))); assert_ok!(Investments::redeem_fulfillment( - investment_id(pool_id, default_tranche_id(pool_id)), + default_investment_id(), FulfillmentWithPrice:: { of_amount: Perquintill::one(), price: Rate::one(), @@ -1649,14 +1574,7 @@ mod non_foreign_currencies { )); // Enable liquidity pool transferability - utils::enable_liquidity_pool_transferability( - currency_id, - Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))), - ); + utils::enable_liquidity_pool_transferability(currency_id); // Mock collection message msg let msg = utils::LiquidityPoolMessage::CollectRedeem { @@ -1691,7 +1609,7 @@ mod non_foreign_currencies { // Order should have been cleared by fulfilling redemption assert_eq!( pallet_investments::Pallet::::acc_active_redeem_order( - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), ) .amount, 0 @@ -1699,7 +1617,7 @@ mod non_foreign_currencies { assert!(!events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), who: investor.clone(), } .into() @@ -1709,7 +1627,7 @@ mod non_foreign_currencies { assert!(!events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount: 0, @@ -1721,7 +1639,7 @@ mod non_foreign_currencies { assert!(events_since_collect.iter().any(|e| { e.event == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), processed_orders: vec![0], who: investor.clone(), collection: RedeemCollection:: { @@ -1736,23 +1654,20 @@ mod non_foreign_currencies { // Foreign CollectedRedemptionTrancheTokens should be killed assert!(!pallet_foreign_investments::CollectedRedemptionTrancheTokens::::contains_key( investor.clone(), - investment_id(pool_id, default_tranche_id(pool_id)) + default_investment_id(), )); // Foreign RedemptionState should be killed assert!(!pallet_foreign_investments::RedemptionState::< DevelopmentRuntime, - >::contains_key( - investor.clone(), - investment_id(pool_id, default_tranche_id(pool_id)) - )); + >::contains_key(investor.clone(), default_investment_id())); // Clearing of foreign RedeemState should be dispatched assert!(events_since_collect.iter().any(|e| { e.event == pallet_foreign_investments::Event::::ForeignRedemptionCleared { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), } .into() })); @@ -1813,7 +1728,7 @@ mod utils { pub const DEFAULT_VALIDITY: Moment = 2555583502; pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); - + pub const DEFAULT_POOL_ID: u64 = 42; pub const DEFAULT_MOONBEAM_LOCATION: MultiLocation = MultiLocation { parents: 1, interior: X1(Parachain(PARA_ID_MOONBEAM)), @@ -1944,7 +1859,7 @@ mod utils { token_name: BoundedVec::< u8, cfg_types::consts::pools::MaxTrancheNameLengthBytes, - >::try_from("A highly advanced tranche".as_bytes().to_vec(),) + >::try_from("A highly advanced tranche".as_bytes().to_vec()) .expect(""), token_symbol: BoundedVec::< u8, @@ -1998,14 +1913,19 @@ mod utils { } /// Enables `LiquidityPoolsTransferable` in the custom asset metadata for - /// the given currency_id. If provided, also updates the location which is - /// required for LiquidityPoolsWrappedToken conversions. - pub fn enable_liquidity_pool_transferability( - currency_id: CurrencyId, - maybe_location: Option>, - ) { + /// the given currency_id. + /// + /// NOTE: Sets the location to the `MOONBEAM_EVM_CHAIN_ID` with dummy + /// address as the location is required for LiquidityPoolsWrappedToken + /// conversions. + pub fn enable_liquidity_pool_transferability(currency_id: CurrencyId) { let metadata = Metadata::::get(currency_id) .expect("Currency should be registered"); + let location = Some(Some(utils::liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))); assert_ok!(OrmlAssetRegistry::update_asset( RuntimeOrigin::root(), @@ -2014,7 +1934,7 @@ mod utils { None, None, None, - maybe_location, + location, Some(CustomMetadata { // Changed: Allow liquidity_pools transferability transferability: CrossChainTransferability::LiquidityPools, @@ -2051,14 +1971,11 @@ mod utils { pub mod investments { use super::*; - /// Returns the investment account of the given investment_id. - pub fn investment_account(investment_id: cfg_types::tokens::TrancheCurrency) -> AccountId { - InvestmentAccount { investment_id }.into_account_truncating() - } - - pub fn default_investment_account(pool_id: u64) -> AccountId { + /// Returns the default investment account derived from the + /// `DEFAULT_POOL_ID` and its default tranche. + pub fn default_investment_account() -> AccountId { InvestmentAccount { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), } .into_account_truncating() } @@ -2073,6 +1990,13 @@ mod utils { ) } + pub fn default_investment_id() -> cfg_types::tokens::TrancheCurrency { + ::TrancheCurrency::generate( + DEFAULT_POOL_ID, + default_tranche_id(DEFAULT_POOL_ID), + ) + } + /// Returns the tranche id at index 0 for the given pool id. pub fn default_tranche_id(pool_id: u64) -> TrancheId { let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); @@ -2133,10 +2057,8 @@ mod utils { )), )); - let amount_before = OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))), - ); + let amount_before = + OrmlTokens::free_balance(currency_id, &default_investment_account()); let final_amount = amount_before .ensure_add(amount) .expect("Should not overflow when incrementing amount"); @@ -2149,16 +2071,13 @@ mod utils { // Verify investment was transferred into investment account assert_eq!( - OrmlTokens::free_balance( - currency_id, - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) - ), + OrmlTokens::free_balance(currency_id, &default_investment_account()), final_amount ); assert!(System::events().iter().any(|e| { e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), state: InvestState::InvestmentOngoing { invest_amount: final_amount }, @@ -2168,7 +2087,7 @@ mod utils { assert_eq!( System::events().iter().last().unwrap().event, pallet_investments::Event::::InvestOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor, amount: final_amount @@ -2197,7 +2116,7 @@ mod utils { // Fund `DomainLocator` account of origination domain as redeemed tranche tokens // are transferred from this account instead of minting assert_ok!(OrmlTokens::mint_into( - investment_id(pool_id, default_tranche_id(pool_id)).into(), + default_investment_id().into(), &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), amount )); @@ -2205,16 +2124,13 @@ mod utils { // Verify redemption has not been made yet assert_eq!( OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + default_investment_id().into(), + &default_investment_account(), ), 0 ); assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investor - ), + OrmlTokens::free_balance(default_investment_id().into(), &investor), 0 ); @@ -2253,21 +2169,18 @@ mod utils { // Verify redemption was transferred into investment account assert_eq!( OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investment_account(investment_id(pool_id, default_tranche_id(pool_id))) + default_investment_id().into(), + &default_investment_account(), ), amount ); assert_eq!( - OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), - &investor - ), + OrmlTokens::free_balance(default_investment_id().into(), &investor), 0 ); assert_eq!( OrmlTokens::free_balance( - investment_id(pool_id, default_tranche_id(pool_id)).into(), + default_investment_id().into(), &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) ), 0 @@ -2276,7 +2189,7 @@ mod utils { System::events().iter().nth_back(4).unwrap().event, pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), state: RedeemState::NotInvestedAnd { inner: InnerRedeemState::Redeeming { redeem_amount: amount @@ -2288,7 +2201,7 @@ mod utils { assert_eq!( System::events().iter().last().unwrap().event, pallet_investments::Event::::RedeemOrderUpdated { - investment_id: investment_id(pool_id, default_tranche_id(pool_id)), + investment_id: default_investment_id(), submitted_at: 0, who: investor.clone(), amount From 3606df98063e872f277d2dfd176153b5cf9fffd1 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 23 Aug 2023 10:36:52 +0200 Subject: [PATCH 50/96] wip: split up liquidity pools tests --- pallets/foreign-investments/src/impls/mod.rs | 4 + pallets/liquidity-pools/src/hooks.rs | 18 + pallets/liquidity-pools/src/inbound.rs | 4 + .../development/tests/liquidity_pools.rs | 2222 ----------------- .../tests/liquidity_pools/add_allow.rs | 636 +++++ .../liquidity_pools/foreign_investments.rs | 23 + .../development/tests/liquidity_pools/mod.rs | 59 + .../non_foreign_investments.rs | 891 +++++++ .../tests/liquidity_pools/setup.rs | 373 +++ .../tests/liquidity_pools/transfers.rs | 488 ++++ 10 files changed, 2496 insertions(+), 2222 deletions(-) delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 7ad1ab8e11..b425f40bdd 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -152,6 +152,10 @@ impl ForeignInvestment for Pallet { log::debug!("InvestState transition error: {:?}", e); Error::::from(InvestError::Decrease) })?; + #[cfg(feature = "std")] + { + dbg!(pre_state, post_state); + } Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 0cc20c2022..e637f6e2db 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -54,7 +54,16 @@ where let wrapped_token = Pallet::::try_get_wrapped_token(&status.foreign_currency)?; let domain_address: DomainAddress = wrapped_token.into(); + #[cfg(feature = "std")] + { + println!("Before burning"); + dbg!(status.clone()); + } T::Tokens::burn_from(status.foreign_currency, &investor, status.amount_decreased)?; + #[cfg(feature = "std")] + { + println!("After burning"); + } let message: MessageOf = Message::ExecutedDecreaseInvestOrder { pool_id: investment_id.of_pool(), @@ -63,9 +72,18 @@ where currency, currency_payout: status.amount_decreased, }; + #[cfg(feature = "std")] + { + dbg!(message.clone()); + } T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; + #[cfg(feature = "std")] + { + println!("After submitting"); + } + Ok(()) } } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index c0b60b92e6..910385f8ce 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -170,6 +170,10 @@ where ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let amount = T::ForeignInvestment::investment(&investor, invest_id)?; + #[cfg(feature = "std")] + { + dbg!(amount); + } Self::handle_decrease_invest_order(pool_id, tranche_id, investor, currency_index, amount) } diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs deleted file mode 100644 index 9e2f1f4787..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools.rs +++ /dev/null @@ -1,2222 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -use ::xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - prelude::{Parachain, X1, X2}, - VersionedMultiLocation, -}; -use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; -use cfg_traits::{ - investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, - liquidity_pools::{Codec, InboundQueue}, - Permissions as _, PoolMutate, -}; -use cfg_types::{ - domain_address::{Domain, DomainAddress}, - fixed_point::Rate, - investments::{InvestCollection, InvestmentAccount, RedeemCollection}, - orders::FulfillmentWithPrice, - permissions::{PermissionScope, PoolRole, Role, UNION}, - pools::TrancheMetadata, - tokens::{ - CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, - ForeignAssetId, - }, - xcm::XcmMetadata, -}; -use codec::Encode; -use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, - OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, -}; -use frame_support::{ - assert_noop, assert_ok, - dispatch::Weight, - traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, -}; -use hex::FromHex; -use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; -use pallet_investments::CollectOutcome; -use pallet_liquidity_pools::{ - encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, -}; -use pallet_pool_system::{ - pool_types::PoolDetails, - tranches::{TrancheInput, TrancheLoc, TrancheType}, -}; -use runtime_common::{ - account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, -}; -use sp_core::H160; -use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, - BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, -}; -use utils::investments::{default_tranche_id, general_currency_index, investment_id}; -use xcm_emulator::TestExt; - -use crate::{ - liquidity_pools::pallet::development::{ - setup::{cfg, dollar, ALICE, BOB, PARA_ID_MOONBEAM}, - test_net::{Development, Moonbeam, RelayChain, TestNet}, - tests::liquidity_pools::utils::{ - get_default_moonbeam_native_token_location, liquidity_pools_transferable_multilocation, - DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, - }, - }, - utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, - *, -}; - -/// NOTE: We can't actually verify that the messages hits the -/// LiquidityPoolsXcmRouter contract on Moonbeam since that would require a -/// rather heavy e2e setup to emulate, involving depending on Moonbeam's -/// runtime, having said contract deployed to their evm environment, and be able -/// to query the evm side. Instead, these tests verify that - given all -/// pre-requirements are set up correctly - we succeed to send the message from -/// the Centrifuge chain pov. We have other unit tests verifying the -/// LiquidityPools' messages encoding and the encoding of the remote EVM call to -/// be executed on Moonbeam. - -/// Verify that `LiquidityPools::add_pool` succeeds when called with all the -/// necessary requirements. -#[test] -fn add_pool() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - - // Verify that the pool must exist before we can call LiquidityPools::add_pool - assert_noop!( - LiquidityPools::add_pool( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - Domain::EVM(1284), - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); - - // Now create the pool - utils::create_ausd_pool(pool_id); - - // Verify ALICE can't call `add_pool` given she is not the `PoolAdmin` - assert_noop!( - LiquidityPools::add_pool( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - Domain::EVM(1284), - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); - - // Verify that it works if it's BOB calling it (the pool admin) - assert_ok!(LiquidityPools::add_pool( - RuntimeOrigin::signed(BOB.into()), - pool_id, - Domain::EVM(1284), - )); - }); -} - -/// Verify that `LiquidityPools::add_tranche` succeeds when called with all the -/// necessary requirements. We can't actually verify that the call hits the -/// LiquidityPoolsXcmRouter contract on Moonbeam since that would require a very -/// heavy e2e setup to emulate. Instead, here we test that we can send the -/// extrinsic and we have other unit tests verifying the encoding of the remote -/// EVM call to be executed on Moonbeam. -#[test] -fn add_tranche() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - let decimals: u8 = 15; - - // Now create the pool - let pool_id = DEFAULT_POOL_ID; - utils::create_ausd_pool(pool_id); - - // Verify we can't call LiquidityPools::add_tranche with a non-existing - // tranche_id - let nonexistent_tranche = [71u8; 16]; - assert_noop!( - LiquidityPools::add_tranche( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - nonexistent_tranche, - Domain::EVM(1284), - ), - 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!( - LiquidityPools::add_tranche( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - tranche_id, - Domain::EVM(1284), - ), - pallet_liquidity_pools::Error::::NotPoolAdmin - ); - - // Finally, verify we can call LiquidityPools::add_tranche successfully - // when called by the PoolAdmin with the right pool + tranche id pair. - assert_ok!(LiquidityPools::add_tranche( - RuntimeOrigin::signed(BOB.into()), - pool_id, - tranche_id, - Domain::EVM(1284), - )); - }); -} - -#[test] -fn update_member() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - // Now create the pool - let pool_id = DEFAULT_POOL_ID; - utils::create_ausd_pool(pool_id); - let tranche_id = default_tranche_id(pool_id); - - // Finally, verify we can call LiquidityPools::add_tranche successfully - // when given a valid pool + tranche id pair. - let new_member = DomainAddress::EVM(1284, [3; 20]); - let valid_until = utils::DEFAULT_VALIDITY; - - // Make ALICE the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - ALICE.into(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Verify it fails if the destination is not whitelisted yet - assert_noop!( - LiquidityPools::update_member( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - tranche_id, - new_member.clone(), - valid_until, - ), - pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, - ); - - // Whitelist destination as TrancheInvestor of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::signed(ALICE.into()), - Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(new_member.clone()), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - // Verify the Investor role was set as expected in Permissions - assert!(Permissions::has( - PermissionScope::Pool(pool_id), - AccountConverter::::convert(new_member.clone()), - Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)), - )); - - // Verify it now works - assert_ok!(LiquidityPools::update_member( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - tranche_id, - new_member, - valid_until, - )); - - // Verify it cannot be called for another member without whitelisting the domain - // beforehand - assert_noop!( - LiquidityPools::update_member( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - tranche_id, - DomainAddress::EVM(1284, [9; 20]), - valid_until, - ), - pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, - ); - }); -} - -#[test] -fn update_token_price() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - let decimals: u8 = 15; - - // Now create the pool - let pool_id = DEFAULT_POOL_ID; - utils::create_ausd_pool(pool_id); - - // Verify it now works - assert_ok!(LiquidityPools::update_token_price( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - default_tranche_id(pool_id), - Domain::EVM(1284), - )); - }); -} - -#[test] -fn transfer_non_tranche_tokens_from_local() { - TestNet::reset(); - - Development::execute_with(|| { - // Register GLMR and fund BOB - utils::setup_pre_requirements(); - - let initial_balance = 100_000_000; - let amount = initial_balance / 2; - let dest_address = utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM; - let currency_id = AUSD_CURRENCY_ID; - let source_account = BOB; - - // Mint sufficient balance - assert_ok!(OrmlTokens::mint_into( - currency_id, - &source_account.into(), - initial_balance - )); - assert_eq!( - OrmlTokens::free_balance(currency_id, &source_account.into()), - initial_balance - ); - - // Only `ForeignAsset` can be transferred - assert_noop!( - LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - CurrencyId::Tranche(42u64, [0u8; 16]), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::InvalidTransferCurrency - ); - assert_noop!( - LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - CurrencyId::Native, - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - - // Cannot transfer as long as cross chain transferability is disabled - assert_noop!( - LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - currency_id, - dest_address.clone(), - initial_balance, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - - // Enable LiquidityPools transferability - utils::enable_liquidity_pool_transferability(currency_id); - - // Cannot transfer more than owned - assert_noop!( - LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - currency_id, - dest_address.clone(), - initial_balance.saturating_add(1), - ), - orml_tokens::Error::::BalanceTooLow - ); - - assert_ok!(LiquidityPools::transfer( - RuntimeOrigin::signed(source_account.into()), - currency_id, - dest_address.clone(), - amount, - )); - - // The account to which the currency should have been transferred - // to on Centrifuge for bookkeeping purposes. - let domain_account: AccountId = Domain::convert(dest_address.domain()); - // Verify that the correct amount of the token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - OrmlTokens::free_balance(currency_id, &domain_account), - amount - ); - assert_eq!( - OrmlTokens::free_balance(currency_id, &source_account.into()), - initial_balance - amount - ); - }); -} - -#[test] -fn transfer_non_tranche_tokens_to_local() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let initial_balance = utils::DEFAULT_BALANCE_GLMR; - let amount = utils::DEFAULT_BALANCE_GLMR / 2; - let dest_address = utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM; - let currency_id = AUSD_CURRENCY_ID; - let receiver: AccountId = BOB.into(); - - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::Transfer { - currency: general_currency_index(currency_id), - // sender is irrelevant for other -> local - sender: ALICE, - receiver: receiver.clone().into(), - amount, - }; - - assert!(OrmlTokens::total_issuance(currency_id).is_zero()); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify that the correct amount was minted - assert_eq!(OrmlTokens::total_issuance(currency_id), amount); - assert_eq!(OrmlTokens::free_balance(currency_id, &receiver), amount); - - // Verify empty transfers throw - assert_noop!( - LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - utils::LiquidityPoolMessage::Transfer { - currency: general_currency_index(currency_id), - sender: ALICE, - receiver: receiver.into(), - amount: 0, - }, - ), - pallet_liquidity_pools::Error::::InvalidTransferAmount - ); - }); -} - -#[test] -fn transfer_tranche_tokens_from_local() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000; - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let receiver = BOB; - - // Create the pool - utils::create_ausd_pool(pool_id); - - let tranche_tokens: CurrencyId = - cfg_types::tokens::TrancheCurrency::generate(pool_id, default_tranche_id(pool_id)) - .into(); - - // Verify that we first need the destination address to be whitelisted - assert_noop!( - LiquidityPools::transfer_tranche_tokens( - RuntimeOrigin::signed(ALICE.into()), - pool_id, - default_tranche_id(pool_id), - dest_address.clone(), - amount, - ), - pallet_liquidity_pools::Error::::UnauthorizedTransfer - ); - - // Make receiver the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.into(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - let valid_until = u64::MAX; - assert_ok!(Permissions::add( - RuntimeOrigin::signed(receiver.into()), - Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - // Call the LiquidityPools::update_member which ensures the destination address - // is whitelisted. - assert_ok!(LiquidityPools::update_member( - RuntimeOrigin::signed(receiver.into()), - pool_id, - default_tranche_id(pool_id), - dest_address.clone(), - valid_until, - )); - - // Give receiver enough Tranche balance to be able to transfer it - OrmlTokens::deposit(tranche_tokens, &receiver.into(), amount); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!(LiquidityPools::transfer_tranche_tokens( - RuntimeOrigin::signed(receiver.into()), - pool_id, - default_tranche_id(pool_id), - dest_address.clone(), - amount, - )); - - // The account to which the tranche should have been transferred - // to on Centrifuge for bookkeeping purposes. - let domain_account: AccountId = Domain::convert(dest_address.domain()); - - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!( - OrmlTokens::free_balance(tranche_tokens, &domain_account), - amount - ); - assert!(OrmlTokens::free_balance(tranche_tokens, &receiver.into()).is_zero()); - }); -} - -#[test] -fn transfer_tranche_tokens_to_local() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - // Create new pool - let pool_id = DEFAULT_POOL_ID; - utils::create_ausd_pool(pool_id); - - let amount = 100_000_000; - let receiver: AccountId = BOB.into(); - let sender: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - let sending_domain_locator = - Domain::convert(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - let tranche_id = default_tranche_id(pool_id); - let tranche_tokens: CurrencyId = - cfg_types::tokens::TrancheCurrency::generate(pool_id, tranche_id).into(); - let valid_until = u64::MAX; - - // Fund `DomainLocator` account of origination domain tranche tokens are - // transferred from this account instead of minting - assert_ok!(OrmlTokens::mint_into( - tranche_tokens, - &sending_domain_locator, - amount - )); - - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::TransferTrancheTokens { - pool_id, - tranche_id, - sender: sender.address(), - domain: Domain::Centrifuge, - receiver: receiver.clone().into(), - amount, - }; - - // Verify that we first need the receiver to be whitelisted - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::UnauthorizedTransfer - ); - - // Make receiver the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - receiver.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Whitelist destination as TrancheInvestor of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::signed(receiver.clone()), - Role::PoolRole(PoolRole::InvestorAdmin), - receiver.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - // Finally, verify that we can now transfer the tranche to the destination - // address - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify that the correct amount of the Tranche token was transferred - // to the dest domain account on Centrifuge. - assert_eq!(OrmlTokens::free_balance(tranche_tokens, &receiver), amount); - assert!(OrmlTokens::free_balance(tranche_tokens, &sending_domain_locator).is_zero()); - }); -} - -#[test] -/// Try to transfer tranches for non-existing pools or invalid tranche ids for -/// existing pools. -fn transferring_invalid_tranche_tokens_should_fail() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); - - let valid_pool_id: u64 = 42; - utils::create_ausd_pool(valid_pool_id); - let valid_tranche_id = default_tranche_id(valid_pool_id); - let valid_until = u64::MAX; - let transfer_amount = 42; - let invalid_pool_id = valid_pool_id + 1; - let invalid_tranche_id = valid_tranche_id.map(|i| i.saturating_add(1)); - assert!(PoolSystem::pool(invalid_pool_id).is_none()); - - // Make BOB the MembersListAdmin of both pools - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - BOB.into(), - PermissionScope::Pool(valid_pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - BOB.into(), - PermissionScope::Pool(invalid_pool_id), - Role::PoolRole(PoolRole::InvestorAdmin), - )); - - // Give BOB investor role for (valid_pool_id, invalid_tranche_id) and - // (invalid_pool_id, valid_tranche_id) - assert_ok!(Permissions::add( - RuntimeOrigin::signed(BOB.into()), - Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), - PermissionScope::Pool(invalid_pool_id), - Role::PoolRole(PoolRole::TrancheInvestor(valid_tranche_id, valid_until)), - )); - assert_ok!(Permissions::add( - RuntimeOrigin::signed(BOB.into()), - Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), - PermissionScope::Pool(valid_pool_id), - Role::PoolRole(PoolRole::TrancheInvestor(invalid_tranche_id, valid_until)), - )); - assert_noop!( - LiquidityPools::transfer_tranche_tokens( - RuntimeOrigin::signed(BOB.into()), - invalid_pool_id, - valid_tranche_id, - dest_address.clone(), - transfer_amount - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); - assert_noop!( - LiquidityPools::transfer_tranche_tokens( - RuntimeOrigin::signed(BOB.into()), - valid_pool_id, - invalid_tranche_id, - dest_address, - transfer_amount - ), - pallet_liquidity_pools::Error::::TrancheNotFound - ); - }); -} - -#[test] -fn add_currency() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let currency_id = AUSD_CURRENCY_ID; - - // Enable LiquidityPools transferability - utils::enable_liquidity_pool_transferability(currency_id); - - assert_ok!(LiquidityPools::add_currency( - RuntimeOrigin::signed(BOB.into()), - currency_id - )); - }); -} - -#[test] -fn add_currency_should_fail() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - assert_noop!( - LiquidityPools::add_currency( - RuntimeOrigin::signed(BOB.into()), - CurrencyId::ForeignAsset(42) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), CurrencyId::Native), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - LiquidityPools::add_currency( - RuntimeOrigin::signed(BOB.into()), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - assert_noop!( - LiquidityPools::add_currency( - RuntimeOrigin::signed(BOB.into()), - CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) - ), - pallet_liquidity_pools::Error::::AssetNotFound - ); - - // Should fail to add currency_id which is missing a registered - // MultiLocation - let currency_id = CurrencyId::ForeignAsset(100); - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - utils::asset_metadata( - "Test".into(), - "TEST".into(), - 12, - false, - None, - CrossChainTransferability::LiquidityPools, - ), - Some(currency_id) - )); - assert_noop!( - LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); - - // Add convertable MultiLocation to metadata but remove transferability - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add multilocation to metadata for some random EVM chain id for which no - // instance is registered - Some(Some(utils::liquidity_pools_transferable_multilocation( - u64::MAX, - [1u8; 20], - ))), - Some(CustomMetadata { - // Changed: Disallow liquidityPools transferability - transferability: CrossChainTransferability::Xcm(Default::default()), - mintable: Default::default(), - permissioned: Default::default(), - pool_currency: Default::default(), - }), - )); - assert_noop!( - LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - - // Switch transferability from XCM to None - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Changed: Disallow cross chain transferability entirely - transferability: CrossChainTransferability::None, - mintable: Default::default(), - permissioned: Default::default(), - pool_currency: Default::default(), - }) - )); - assert_noop!( - LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - }); -} - -#[test] -fn allow_pool_currency() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let currency_id = AUSD_CURRENCY_ID; - let pool_id = DEFAULT_POOL_ID; - let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; - let evm_address = [1u8; 20]; - - // Create an AUSD pool - utils::create_ausd_pool(pool_id); - - // Enable LiquidityPools transferability - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add location which can be converted to LiquidityPoolsWrappedToken - Some(Some(utils::liquidity_pools_transferable_multilocation( - evm_chain_id, - evm_address, - ))), - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - mintable: Default::default(), - permissioned: Default::default(), - pool_currency: true, - }) - )); - - assert_ok!(LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - default_tranche_id(pool_id), - currency_id, - )); - }); -} - -#[test] -fn allow_pool_should_fail() { - TestNet::reset(); - - Development::execute_with(|| { - let pool_id = DEFAULT_POOL_ID; - let currency_id = CurrencyId::ForeignAsset(42); - let ausd_currency_id = AUSD_CURRENCY_ID; - - utils::setup_pre_requirements(); - // Should fail if pool does not exist - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - // Tranche id is arbitrary in this case as pool does not exist - [0u8; 16], - currency_id, - ), - pallet_liquidity_pools::Error::::PoolNotFound - ); - - // Register currency_id with pool_currency set to true - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - utils::asset_metadata( - "Test".into(), - "TEST".into(), - 12, - true, - None, - Default::default(), - ), - Some(currency_id) - )); - - // Create pool - utils::create_currency_pool(pool_id, currency_id, 10_000 * dollar(12)); - - // Should fail if asset is not pool currency - assert!(currency_id != ausd_currency_id); - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - default_tranche_id(pool_id), - ausd_currency_id, - ), - pallet_liquidity_pools::Error::::InvalidInvestCurrency - ); - - // Should fail if currency is not liquidityPools transferable - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Disallow any cross chain transferability - transferability: CrossChainTransferability::None, - mintable: Default::default(), - permissioned: Default::default(), - // Changed: Allow to be usable as pool currency - pool_currency: true, - }), - )); - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - default_tranche_id(pool_id), - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - - // Should fail if currency does not have any MultiLocation in metadata - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - None, - Some(CustomMetadata { - // Changed: Allow liquidityPools transferability - transferability: CrossChainTransferability::LiquidityPools, - mintable: Default::default(), - permissioned: Default::default(), - // Still allow to be pool currency - pool_currency: true, - }), - )); - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - default_tranche_id(pool_id), - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); - - // Should fail if currency does not have LiquidityPoolsWrappedToken location in - // metadata - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - // Changed: Add some location which cannot be converted to LiquidityPoolsWrappedToken - Some(Some(VersionedMultiLocation::V3(Default::default()))), - // No change for transferability required as it is already allowed for LiquidityPools - None, - )); - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id, - default_tranche_id(pool_id), - currency_id, - ), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken - ); - - // Create new pool for non foreign asset - // NOTE: Can be removed after merging https://github.com/centrifuge/centrifuge-chain/pull/1343 - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - utils::asset_metadata( - "Acala Dollar".into(), - "AUSD".into(), - 12, - true, - None, - Default::default() - ), - Some(CurrencyId::AUSD) - )); - utils::create_currency_pool(pool_id + 1, CurrencyId::AUSD, 10_000 * dollar(12)); - // Should fail if currency is not foreign asset - assert_noop!( - LiquidityPools::allow_pool_currency( - RuntimeOrigin::signed(BOB.into()), - pool_id + 1, - // Tranche id is arbitrary in this case, so we don't need to check for the exact - // pool_id - default_tranche_id(pool_id + 1), - CurrencyId::AUSD, - ), - DispatchError::Token(sp_runtime::TokenError::Unsupported) - ); - }); -} - -mod non_foreign_currencies { - use super::*; - use crate::liquidity_pools::pallet::development::tests::liquidity_pools::utils::investments::{ - default_investment_account, default_investment_id, - }; - - #[test] - fn inbound_increase_invest_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - amount, - investor, - currency_id, - ); - - // Verify the order was updated to the amount - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - amount - ); - }); - } - - #[test] - fn inbound_decrease_invest_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; - let decrease_amount = invest_amount / 3; - let final_amount = invest_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - utils::enable_liquidity_pool_transferability(currency_id); - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - final_amount - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: decrease_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); - } - - #[test] - fn inbound_cancel_invest_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - - // Verify investment account holds funds before cancelling - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - invest_amount - ); - - // Mock incoming cancel message - let msg = utils::LiquidityPoolMessage::CancelInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - utils::enable_liquidity_pool_transferability(currency_id); - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Foreign InvestmentState should be cleared - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(&investor, default_investment_id())); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - - // Verify investment was entirely drained from investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - 0 - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: invest_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - }); - } - - #[test] - fn inbound_collect_invest_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - let investment_currency_id: CurrencyId = default_investment_id().into(); - - // Set permissions and execute initial investment - utils::investments::do_initial_increase_investment( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = System::events(); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_invest_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); - - // Tranche tokens will be minted upon fulfillment - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); - - // Mock collection message msg - let msg = utils::LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); - - // Verify investment was transferred to the domain locator - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - amount - ); - - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: default_investment_id(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - // Foreign InvestmentState should be killed - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Clearing of foreign InvestState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignInvestmentCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - }); - } - - #[test] - fn inbound_increase_redeem_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - utils::investments::do_initial_increase_redemption( - pool_id, - amount, - investor, - currency_id, - ); - - // Verify amount was noted in the corresponding order - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - amount - ); - }); - } - - #[test] - fn inbound_decrease_redeem_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let redeem_amount = 100_000_000; - let decrease_amount = redeem_amount / 3; - let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = - Domain::convert(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - utils::investments::do_initial_increase_redemption( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); - - // Mock incoming decrease message - let msg = utils::LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - final_amount - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - decrease_amount - ); - - assert!(System::events().iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: RedeemState::InvestedAnd { - invest_amount: decrease_amount, - inner: InnerRedeemState::Redeeming { - redeem_amount: final_amount - } - } - } - .into() - })); - - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); - } - - #[test] - fn inbound_collect_redeem_order() { - TestNet::reset(); - - Development::execute_with(|| { - utils::setup_pre_requirements(); - - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); - - // Create new pool - utils::create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - utils::investments::do_initial_increase_redemption( - pool_id, - amount, - investor.clone(), - currency_id, - ); - let events_before_collect = System::events(); - - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_redeem_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); - assert_ok!(Investments::redeem_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - - // Enable liquidity pool transferability - utils::enable_liquidity_pool_transferability(currency_id); - - // Mock collection message msg - let msg = utils::LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); - - // Verify collected redemption was burned from investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount - } - .into())); - - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: default_investment_id(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: amount, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - // Foreign CollectedRedemptionTrancheTokens should be killed - assert!(!pallet_foreign_investments::CollectedRedemptionTrancheTokens::::contains_key( - investor.clone(), - default_investment_id(), - )); - - // Foreign RedemptionState should be killed - assert!(!pallet_foreign_investments::RedemptionState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Clearing of foreign RedeemState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - }); - } -} - -#[test] -fn test_vec_to_fixed_array() { - let src = "TrNcH".as_bytes().to_vec(); - let symbol: [u8; 32] = cfg_utils::vec_to_fixed_array(src); - - assert!(symbol.starts_with("TrNcH".as_bytes())); - - assert_eq!( - symbol, - [ - 84, 114, 78, 99, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 - ] - ); -} - -// Verify that the max tranche token symbol and name lengths are what the -// LiquidityPools pallet expects. -#[test] -fn verify_tranche_fields_sizes() { - assert_eq!( - cfg_types::consts::pools::MaxTrancheNameLengthBytes::get(), - pallet_liquidity_pools::TOKEN_NAME_SIZE as u32 - ); - assert_eq!( - cfg_types::consts::pools::MaxTrancheSymbolLengthBytes::get(), - pallet_liquidity_pools::TOKEN_SYMBOL_SIZE as u32 - ); -} - -mod utils { - use cfg_primitives::Moment; - use cfg_types::tokens::CrossChainTransferability; - use liquidity_pools_gateway_routers::{ - ethereum_xcm::EthereumXCMRouter, DomainRouter, XCMRouter, XcmTransactInfo, - }; - use orml_asset_registry::Metadata; - - use super::*; - use crate::{ - chain::centrifuge::development, - liquidity_pools::pallet::development::tests::register_ausd, - utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, - }; - - pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; - pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); - pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; - pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = - DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, DEFAULT_EVM_ADDRESS_MOONBEAM); - pub const DEFAULT_VALIDITY: Moment = 2555583502; - pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = - DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); - pub const DEFAULT_POOL_ID: u64 = 42; - pub const DEFAULT_MOONBEAM_LOCATION: MultiLocation = MultiLocation { - parents: 1, - interior: X1(Parachain(PARA_ID_MOONBEAM)), - }; - - pub type LiquidityPoolMessage = Message; - - pub fn get_default_moonbeam_native_token_location() -> MultiLocation { - MultiLocation { - parents: 1, - interior: X2(Parachain(PARA_ID_MOONBEAM), general_key(&[0, 1])), - } - } - - pub fn set_test_domain_router( - evm_chain_id: u64, - xcm_domain_location: VersionedMultiLocation, - currency_id: CurrencyId, - fee_location: VersionedMultiLocation, - ) { - let ethereum_xcm_router = EthereumXCMRouter:: { - router: XCMRouter { - xcm_domain: GatewayXcmDomain { - location: Box::new(xcm_domain_location), - ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), - contract_address: H160::from(utils::DEFAULT_EVM_ADDRESS_MOONBEAM), - max_gas_limit: 700_000, - transact_info: XcmTransactInfo { - transact_extra_weight: 1.into(), - max_weight: 8_000_000_000_000_000.into(), - transact_extra_weight_signed: Some(3.into()), - }, - fee_currency: currency_id, - fee_per_second: default_per_second(18), - fee_asset_location: Box::new(fee_location), - }, - _marker: Default::default(), - }, - _marker: Default::default(), - }; - - let domain_router = DomainRouter::EthereumXCM(ethereum_xcm_router); - let domain = Domain::EVM(evm_chain_id); - - assert_ok!(LiquidityPoolsGateway::set_domain_router( - RuntimeOrigin::root(), - domain, - domain_router, - )); - } - - /// Initializes universally required storage for liquidityPools tests: - /// * Set the EthereumXCM router which in turn sets: - /// * transact info and domain router for Moonbeam `MultiLocation`, - /// * fee for GLMR (`GLIMMER_CURRENCY_ID`), - /// * Register GLMR and AUSD in `OrmlAssetRegistry`, - /// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice, Bob and the - /// Treasury. - /// - /// NOTE: AUSD is the default pool currency in `create_pool`. - /// Neither AUSD nor GLMR are registered as a liquidityPools-transferable - /// currency! - pub fn setup_pre_requirements() { - /// Set the EthereumXCM router necessary for Moonbeam. - set_test_domain_router( - MOONBEAM_EVM_CHAIN_ID, - DEFAULT_MOONBEAM_LOCATION.into(), - GLIMMER_CURRENCY_ID, - get_default_moonbeam_native_token_location().into(), - ); - - /// Register Moonbeam's native token - assert_ok!(OrmlAssetRegistry::register_asset( - RuntimeOrigin::root(), - utils::asset_metadata( - "Glimmer".into(), - "GLMR".into(), - 18, - false, - Some(VersionedMultiLocation::V3( - get_default_moonbeam_native_token_location() - )), - CrossChainTransferability::Xcm(Default::default()), - ), - Some(GLIMMER_CURRENCY_ID) - )); - - // Give Alice, Bob and Treasury enough glimmer to pay for fees - OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &ALICE.into(), DEFAULT_BALANCE_GLMR); - OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &BOB.into(), DEFAULT_BALANCE_GLMR); - // Treasury pays for `Executed*` messages - OrmlTokens::deposit( - GLIMMER_CURRENCY_ID, - &TreasuryPalletId::get().into_account_truncating(), - DEFAULT_BALANCE_GLMR, - ); - - // Register AUSD in the asset registry which is the default pool currency in - // `create_pool` - register_ausd(); - } - - /// Creates a new pool for the given id with - /// * BOB as admin and depositor - /// * Two tranches - /// * AUSD as pool currency with max reserve 10k. - pub fn create_ausd_pool(pool_id: u64) { - create_currency_pool(pool_id, AUSD_CURRENCY_ID, dollar(currency_decimals::AUSD)) - } - - /// Creates a new pool for for the given id with the provided currency. - /// * BOB as admin and depositor - /// * Two tranches - /// * The given `currency` as pool currency with of `currency_decimals`. - pub fn create_currency_pool(pool_id: u64, currency_id: CurrencyId, currency_decimals: Balance) { - assert_ok!(PoolSystem::create( - BOB.into(), - BOB.into(), - pool_id, - vec![ - TrancheInput { - tranche_type: TrancheType::Residual, - seniority: None, - metadata: TrancheMetadata { - // NOTE: For now, we have to set these metadata fields of the first tranche - // to be convertible to the 32-byte size expected by the liquidity pools - // AddTranche message. - token_name: BoundedVec::< - u8, - cfg_types::consts::pools::MaxTrancheNameLengthBytes, - >::try_from("A highly advanced tranche".as_bytes().to_vec()) - .expect(""), - token_symbol: BoundedVec::< - u8, - cfg_types::consts::pools::MaxTrancheSymbolLengthBytes, - >::try_from("TrNcH".as_bytes().to_vec()) - .expect(""), - } - }, - TrancheInput { - tranche_type: TrancheType::NonResidual { - interest_rate_per_sec: One::one(), - min_risk_buffer: Perquintill::from_percent(10), - }, - seniority: None, - metadata: TrancheMetadata { - token_name: BoundedVec::default(), - token_symbol: BoundedVec::default(), - } - } - ], - currency_id, - currency_decimals, - )); - } - - /// Returns a `VersionedMultiLocation` that can be converted into - /// `LiquidityPoolsWrappedToken` which is required for cross chain asset - /// registration and transfer. - pub fn liquidity_pools_transferable_multilocation( - chain_id: u64, - address: [u8; 20], - ) -> VersionedMultiLocation { - VersionedMultiLocation::V3(MultiLocation { - parents: 0, - interior: - X3( - PalletInstance( - ::PalletInfo::index::< - LiquidityPools, - >() - .expect("LiquidityPools should have pallet index") - .saturated_into(), - ), - GlobalConsensus(NetworkId::Ethereum { chain_id }), - AccountKey20 { - network: None, - key: address, - }, - ), - }) - } - - /// Enables `LiquidityPoolsTransferable` in the custom asset metadata for - /// the given currency_id. - /// - /// NOTE: Sets the location to the `MOONBEAM_EVM_CHAIN_ID` with dummy - /// address as the location is required for LiquidityPoolsWrappedToken - /// conversions. - pub fn enable_liquidity_pool_transferability(currency_id: CurrencyId) { - let metadata = Metadata::::get(currency_id) - .expect("Currency should be registered"); - let location = Some(Some(utils::liquidity_pools_transferable_multilocation( - MOONBEAM_EVM_CHAIN_ID, - // Value of evm_address is irrelevant here - [1u8; 20], - ))); - - assert_ok!(OrmlAssetRegistry::update_asset( - RuntimeOrigin::root(), - currency_id, - None, - None, - None, - None, - location, - Some(CustomMetadata { - // Changed: Allow liquidity_pools transferability - transferability: CrossChainTransferability::LiquidityPools, - ..metadata.additional - }) - )); - } - - /// Returns metadata for the given data with existential deposit of - /// 1_000_000. - pub fn asset_metadata( - name: Vec, - symbol: Vec, - decimals: u32, - is_pool_currency: bool, - location: Option, - transferability: CrossChainTransferability, - ) -> AssetMetadata { - AssetMetadata { - name, - symbol, - decimals, - location, - existential_deposit: 1_000_000, - additional: CustomMetadata { - transferability, - mintable: false, - permissioned: false, - pool_currency: is_pool_currency, - }, - } - } - - pub mod investments { - use super::*; - - /// Returns the default investment account derived from the - /// `DEFAULT_POOL_ID` and its default tranche. - pub fn default_investment_account() -> AccountId { - InvestmentAccount { - investment_id: default_investment_id(), - } - .into_account_truncating() - } - - /// Returns the investment_id of the given pool and tranche ids. - pub fn investment_id( - pool_id: u64, - tranche_id: TrancheId, - ) -> cfg_types::tokens::TrancheCurrency { - ::TrancheCurrency::generate( - pool_id, tranche_id, - ) - } - - pub fn default_investment_id() -> cfg_types::tokens::TrancheCurrency { - ::TrancheCurrency::generate( - DEFAULT_POOL_ID, - default_tranche_id(DEFAULT_POOL_ID), - ) - } - - /// Returns the tranche id at index 0 for the given pool id. - pub fn default_tranche_id(pool_id: u64) -> TrancheId { - let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); - pool_details - .tranches - .tranche_id(TrancheLoc::Index(0)) - .expect("Tranche at index 0 exists") - } - - /// Returns the derived general currency index. - /// - /// Throws if the provided currency_id is not - /// `CurrencyId::ForeignAsset(id)`. - pub fn general_currency_index(currency_id: CurrencyId) -> u128 { - pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) - .expect("ForeignAsset should convert into u128") - } - - /// Sets up required permissions for the investor and executes an - /// initial investment via LiquidityPools by executing - /// `IncreaseInvestOrder`. - /// - /// Assumes `utils::setup_pre_requirements` and - /// `utils::investments::create_currency_pool` to have been called - /// beforehand - pub fn do_initial_increase_investment( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let valid_until = utils::DEFAULT_VALIDITY; - - // Mock incoming increase invest message - let msg = utils::LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount, - }; - - // Should fail if investor does not have investor role yet - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - - // Make investor the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - investor.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - let amount_before = - OrmlTokens::free_balance(currency_id, &default_investment_account()); - let final_amount = amount_before - .ensure_add(amount) - .expect("Should not overflow when incrementing amount"); - - // Execute byte message - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify investment was transferred into investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - final_amount - ); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: InvestState::InvestmentOngoing { - invest_amount: final_amount - }, - } - .into() - })); - assert_eq!( - System::events().iter().last().unwrap().event, - pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor, - amount: final_amount - } - .into() - ); - } - - /// Sets up required permissions for the investor and executes an - /// initial redemption via LiquidityPools by executing - /// `IncreaseRedeemOrder`. - /// - /// Assumes `utils::setup_pre_requirements` and - /// `utils::investments::create_currency_pool` to have been called - /// beforehand. - /// - /// NOTE: Mints exactly the redeeming amount of tranche tokens. - pub fn do_initial_increase_redemption( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let valid_until = utils::DEFAULT_VALIDITY; - - // Fund `DomainLocator` account of origination domain as redeemed tranche tokens - // are transferred from this account instead of minting - assert_ok!(OrmlTokens::mint_into( - default_investment_id().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount - )); - - // Verify redemption has not been made yet - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - - // Mock incoming increase invest message - let msg = utils::LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id: 42, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount, - }; - - // Should fail if investor does not have investor role yet - assert_noop!( - LiquidityPools::submit(utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - - // Make investor the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - investor.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - assert_ok!(LiquidityPools::submit( - utils::DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - msg - )); - - // Verify redemption was transferred into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - amount - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) - ), - 0 - ); - assert_eq!( - System::events().iter().nth_back(4).unwrap().event, - pallet_foreign_investments::Event::::ForeignRedemptionUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: amount - } - }, - } - .into() - ); - assert_eq!( - System::events().iter().last().unwrap().event, - pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount - } - .into() - ); - - // Verify order id is 0 - assert_eq!( - pallet_investments::Pallet::::redeem_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); - } - } -} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs new file mode 100644 index 0000000000..663a18b846 --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs @@ -0,0 +1,636 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +use ::xcm::{ + latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, + prelude::{Parachain, X1, X2}, + VersionedMultiLocation, +}; +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; +use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + liquidity_pools::{Codec, InboundQueue}, + Permissions as _, PoolMutate, +}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + investments::{InvestCollection, InvestmentAccount, RedeemCollection}, + orders::FulfillmentWithPrice, + permissions::{PermissionScope, PoolRole, Role, UNION}, + pools::TrancheMetadata, + tokens::{ + CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, + ForeignAssetId, + }, + xcm::XcmMetadata, +}; +use codec::Encode; +use development_runtime::{ + Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, + OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, +}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Weight, + traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, +}; +use hex::FromHex; +use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; +use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; +use pallet_investments::CollectOutcome; +use pallet_liquidity_pools::{ + encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, +}; +use pallet_pool_system::{ + pool_types::PoolDetails, + tranches::{TrancheInput, TrancheLoc, TrancheType}, +}; +use runtime_common::{ + account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, +}; +use sp_core::H160; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, + BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, +}; +use xcm_emulator::TestExt; + +use crate::{ + liquidity_pools::pallet::development::{ + setup::{dollar, ALICE, BOB}, + test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::liquidity_pools::setup::{ + asset_metadata, create_ausd_pool, create_currency_pool, + enable_liquidity_pool_transferability, + investments::{ + default_investment_account, default_investment_id, default_tranche_id, + general_currency_index, investment_id, + }, + liquidity_pools_transferable_multilocation, set_test_domain_router, + setup_pre_requirements, DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, + }, + }, + utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, +}; + +/// NOTE: We can't actually verify that the messages hits the +/// LiquidityPoolsXcmRouter contract on Moonbeam since that would require a +/// rather heavy e2e setup to emulate, involving depending on Moonbeam's +/// runtime, having said contract deployed to their evm environment, and be able +/// to query the evm side. Instead, these tests verify that - given all +/// pre-requirements are set up correctly - we succeed to send the message from +/// the Centrifuge chain pov. We have other unit tests verifying the +/// LiquidityPools' messages encoding and the encoding of the remote EVM call to +/// be executed on Moonbeam. +/// Verify that `LiquidityPools::add_pool` succeeds when called with all the +/// necessary requirements. +#[test] +fn add_pool() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + + // Verify that the pool must exist before we can call LiquidityPools::add_pool + assert_noop!( + LiquidityPools::add_pool( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + Domain::EVM(1284), + ), + 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!( + LiquidityPools::add_pool( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + Domain::EVM(1284), + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); + + // Verify that it works if it's BOB calling it (the pool admin) + assert_ok!(LiquidityPools::add_pool( + RuntimeOrigin::signed(BOB.into()), + pool_id, + Domain::EVM(1284), + )); + }); +} + +/// Verify that `LiquidityPools::add_tranche` succeeds when called with all the +/// necessary requirements. We can't actually verify that the call hits the +/// LiquidityPoolsXcmRouter contract on Moonbeam since that would require a very +/// heavy e2e setup to emulate. Instead, here we test that we can send the +/// extrinsic and we have other unit tests verifying the encoding of the remote +/// EVM call to be executed on Moonbeam. +#[test] +fn add_tranche() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + let decimals: u8 = 15; + + // Now create the pool + let pool_id = DEFAULT_POOL_ID; + create_ausd_pool(pool_id); + + // Verify we can't call LiquidityPools::add_tranche with a non-existing + // tranche_id + let nonexistent_tranche = [71u8; 16]; + assert_noop!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + nonexistent_tranche, + Domain::EVM(1284), + ), + 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!( + LiquidityPools::add_tranche( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + tranche_id, + Domain::EVM(1284), + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); + + // Finally, verify we can call LiquidityPools::add_tranche successfully + // when called by the PoolAdmin with the right pool + tranche id pair. + assert_ok!(LiquidityPools::add_tranche( + RuntimeOrigin::signed(BOB.into()), + pool_id, + tranche_id, + Domain::EVM(1284), + )); + }); +} + +#[test] +fn update_member() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + // Now create the pool + let pool_id = DEFAULT_POOL_ID; + create_ausd_pool(pool_id); + let tranche_id = default_tranche_id(pool_id); + + // Finally, verify we can call LiquidityPools::add_tranche successfully + // when given a valid pool + tranche id pair. + let new_member = DomainAddress::EVM(1284, [3; 20]); + let valid_until = DEFAULT_VALIDITY; + + // Make ALICE the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + ALICE.into(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); + + // Verify it fails if the destination is not whitelisted yet + assert_noop!( + LiquidityPools::update_member( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + tranche_id, + new_member.clone(), + valid_until, + ), + pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, + ); + + // Whitelist destination as TrancheInvestor of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::signed(ALICE.into()), + Role::PoolRole(PoolRole::InvestorAdmin), + AccountConverter::::convert(new_member.clone()), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + // Verify the Investor role was set as expected in Permissions + assert!(Permissions::has( + PermissionScope::Pool(pool_id), + AccountConverter::::convert(new_member.clone()), + Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)), + )); + + // Verify it now works + assert_ok!(LiquidityPools::update_member( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + tranche_id, + new_member, + valid_until, + )); + + // Verify it cannot be called for another member without whitelisting the domain + // beforehand + assert_noop!( + LiquidityPools::update_member( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + tranche_id, + DomainAddress::EVM(1284, [9; 20]), + valid_until, + ), + pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, + ); + }); +} + +#[test] +fn update_token_price() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + let decimals: u8 = 15; + + // Now create the pool + let pool_id = DEFAULT_POOL_ID; + create_ausd_pool(pool_id); + + // Verify it now works + assert_ok!(LiquidityPools::update_token_price( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + default_tranche_id(pool_id), + Domain::EVM(1284), + )); + }); +} + +#[test] +fn add_currency() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let currency_id = AUSD_CURRENCY_ID; + + // Enable LiquidityPools transferability + enable_liquidity_pool_transferability(currency_id); + + assert_ok!(LiquidityPools::add_currency( + RuntimeOrigin::signed(BOB.into()), + currency_id + )); + }); +} + +#[test] +fn add_currency_should_fail() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + assert_noop!( + LiquidityPools::add_currency( + RuntimeOrigin::signed(BOB.into()), + CurrencyId::ForeignAsset(42) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), CurrencyId::Native), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + LiquidityPools::add_currency( + RuntimeOrigin::signed(BOB.into()), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + LiquidityPools::add_currency( + RuntimeOrigin::signed(BOB.into()), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards) + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + + // Should fail to add currency_id which is missing a registered + // MultiLocation + let currency_id = CurrencyId::ForeignAsset(100); + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + asset_metadata( + "Test".into(), + "TEST".into(), + 12, + false, + None, + CrossChainTransferability::LiquidityPools, + ), + Some(currency_id) + )); + assert_noop!( + LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); + + // Add convertable MultiLocation to metadata but remove transferability + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add multilocation to metadata for some random EVM chain id for which no + // instance is registered + Some(Some(liquidity_pools_transferable_multilocation( + u64::MAX, + [1u8; 20], + ))), + Some(CustomMetadata { + // Changed: Disallow liquidityPools transferability + transferability: CrossChainTransferability::Xcm(Default::default()), + mintable: Default::default(), + permissioned: Default::default(), + pool_currency: Default::default(), + }), + )); + assert_noop!( + LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + + // Switch transferability from XCM to None + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Changed: Disallow cross chain transferability entirely + transferability: CrossChainTransferability::None, + mintable: Default::default(), + permissioned: Default::default(), + pool_currency: Default::default(), + }) + )); + assert_noop!( + LiquidityPools::add_currency(RuntimeOrigin::signed(BOB.into()), currency_id), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + }); +} + +#[test] +fn allow_pool_currency() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let currency_id = AUSD_CURRENCY_ID; + let pool_id = DEFAULT_POOL_ID; + let evm_chain_id: u64 = MOONBEAM_EVM_CHAIN_ID; + let evm_address = [1u8; 20]; + + // Create an AUSD pool + create_ausd_pool(pool_id); + + // Enable LiquidityPools transferability + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add location which can be converted to LiquidityPoolsWrappedToken + Some(Some(liquidity_pools_transferable_multilocation( + evm_chain_id, + evm_address, + ))), + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + mintable: Default::default(), + permissioned: Default::default(), + pool_currency: true, + }) + )); + + assert_ok!(LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + default_tranche_id(pool_id), + currency_id, + )); + }); +} + +#[test] +fn allow_pool_should_fail() { + TestNet::reset(); + + Development::execute_with(|| { + let pool_id = DEFAULT_POOL_ID; + let currency_id = CurrencyId::ForeignAsset(42); + let ausd_currency_id = AUSD_CURRENCY_ID; + + setup_pre_requirements(); + // Should fail if pool does not exist + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + // Tranche id is arbitrary in this case as pool does not exist + [0u8; 16], + currency_id, + ), + pallet_liquidity_pools::Error::::PoolNotFound + ); + + // Register currency_id with pool_currency set to true + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + asset_metadata( + "Test".into(), + "TEST".into(), + 12, + true, + None, + Default::default(), + ), + Some(currency_id) + )); + + // Create pool + create_currency_pool(pool_id, currency_id, 10_000 * dollar(12)); + + // Should fail if asset is not pool currency + assert!(currency_id != ausd_currency_id); + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + default_tranche_id(pool_id), + ausd_currency_id, + ), + pallet_liquidity_pools::Error::::InvalidInvestCurrency + ); + + // Should fail if currency is not liquidityPools transferable + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Disallow any cross chain transferability + transferability: CrossChainTransferability::None, + mintable: Default::default(), + permissioned: Default::default(), + // Changed: Allow to be usable as pool currency + pool_currency: true, + }), + )); + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + default_tranche_id(pool_id), + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + + // Should fail if currency does not have any MultiLocation in metadata + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + None, + Some(CustomMetadata { + // Changed: Allow liquidityPools transferability + transferability: CrossChainTransferability::LiquidityPools, + mintable: Default::default(), + permissioned: Default::default(), + // Still allow to be pool currency + pool_currency: true, + }), + )); + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + default_tranche_id(pool_id), + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); + + // Should fail if currency does not have LiquidityPoolsWrappedToken location in + // metadata + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + // Changed: Add some location which cannot be converted to LiquidityPoolsWrappedToken + Some(Some(VersionedMultiLocation::V3(Default::default()))), + // No change for transferability required as it is already allowed for LiquidityPools + None, + )); + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id, + default_tranche_id(pool_id), + currency_id, + ), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsWrappedToken + ); + + // Create new pool for non foreign asset + // NOTE: Can be removed after merging https://github.com/centrifuge/centrifuge-chain/pull/1343 + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + asset_metadata( + "Acala Dollar".into(), + "AUSD".into(), + 12, + true, + None, + Default::default() + ), + Some(CurrencyId::AUSD) + )); + create_currency_pool(pool_id + 1, CurrencyId::AUSD, 10_000 * dollar(12)); + // Should fail if currency is not foreign asset + assert_noop!( + LiquidityPools::allow_pool_currency( + RuntimeOrigin::signed(BOB.into()), + pool_id + 1, + // Tranche id is arbitrary in this case, so we don't need to check for the exact + // pool_id + default_tranche_id(pool_id + 1), + CurrencyId::AUSD, + ), + DispatchError::Token(sp_runtime::TokenError::Unsupported) + ); + }); +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs new file mode 100644 index 0000000000..609c4437c8 --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -0,0 +1,23 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs new file mode 100644 index 0000000000..8e6ef17051 --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs @@ -0,0 +1,59 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +mod add_allow; +mod foreign_investments; +mod non_foreign_investments; +mod setup; +mod transfers; + +#[test] +fn test_vec_to_fixed_array() { + let src = "TrNcH".as_bytes().to_vec(); + let symbol: [u8; 32] = cfg_utils::vec_to_fixed_array(src); + + assert!(symbol.starts_with("TrNcH".as_bytes())); + + assert_eq!( + symbol, + [ + 84, 114, 78, 99, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ] + ); +} + +// Verify that the max tranche token symbol and name lengths are what the +// LiquidityPools pallet expects. +#[test] +fn verify_tranche_fields_sizes() { + assert_eq!( + cfg_types::consts::pools::MaxTrancheNameLengthBytes::get(), + pallet_liquidity_pools::TOKEN_NAME_SIZE as u32 + ); + assert_eq!( + cfg_types::consts::pools::MaxTrancheSymbolLengthBytes::get(), + pallet_liquidity_pools::TOKEN_SYMBOL_SIZE as u32 + ); +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs new file mode 100644 index 0000000000..531d2449aa --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -0,0 +1,891 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +use ::xcm::{ + latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, + prelude::{Parachain, X1, X2}, + VersionedMultiLocation, +}; +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; +use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + liquidity_pools::{Codec, InboundQueue}, + Permissions as _, PoolMutate, +}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + investments::{InvestCollection, InvestmentAccount, RedeemCollection}, + orders::FulfillmentWithPrice, + permissions::{PermissionScope, PoolRole, Role, UNION}, + pools::TrancheMetadata, + tokens::{ + CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, + ForeignAssetId, + }, + xcm::XcmMetadata, +}; +use codec::Encode; +use development_runtime::{ + Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, + OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, +}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Weight, + traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, +}; +use hex::FromHex; +use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; +use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; +use pallet_investments::CollectOutcome; +use pallet_liquidity_pools::{ + encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, +}; +use pallet_pool_system::{ + pool_types::PoolDetails, + tranches::{TrancheInput, TrancheLoc, TrancheType}, +}; +use runtime_common::{ + account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, +}; +use sp_core::H160; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, + BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, +}; +use xcm_emulator::TestExt; + +use crate::{ + liquidity_pools::pallet::development::{ + setup::{dollar, ALICE, BOB}, + test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::liquidity_pools::{ + non_foreign_investments::setup::{do_initial_increase_investment, do_initial_increase_redemption}, + setup::{ + asset_metadata, create_ausd_pool, create_currency_pool, + enable_liquidity_pool_transferability, + investments::{ + default_investment_account, default_investment_id, default_tranche_id, + general_currency_index, investment_id, + }, + liquidity_pools_transferable_multilocation, set_test_domain_router, + setup_pre_requirements, LiquidityPoolMessage, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, + }, + }, + }, + utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, +}; + +#[test] +fn inbound_increase_invest_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor, currency_id); + + // Verify the order was updated to the amount + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + amount + ); + }); +} + +#[test] +fn inbound_decrease_invest_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let decrease_amount = invest_amount / 3; + let final_amount = invest_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + enable_liquidity_pool_transferability(currency_id); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + final_amount + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); +} + +#[test] +fn inbound_cancel_invest_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + + // Verify investment account holds funds before cancelling + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + invest_amount + ); + + // Mock incoming cancel message + let msg = LiquidityPoolMessage::CancelInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + enable_liquidity_pool_transferability(currency_id); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Foreign InvestmentState should be cleared + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(&investor, default_investment_id())); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + + // Verify investment was entirely drained from investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + 0 + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: invest_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); +} + +#[test] +fn inbound_collect_invest_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + let investment_currency_id: CurrencyId = default_investment_id().into(); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::InvestCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_invest_orders(investment_id( + pool_id, + default_tranche_id(pool_id) + ))); + + // Tranche tokens will be minted upon fulfillment + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); + + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify investment was transferred to the domain locator + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + amount + ); + + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign InvestmentState should be killed + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Clearing of foreign InvestState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + }); +} + +#[test] +fn inbound_increase_redeem_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, amount, investor, currency_id); + + // Verify amount was noted in the corresponding order + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + amount + ); + }); +} + +#[test] +fn inbound_decrease_redeem_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let decrease_amount = redeem_amount / 3; + let final_amount = redeem_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); + + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + final_amount + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + decrease_amount + ); + + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::InvestedAnd { + invest_amount: decrease_amount, + inner: InnerRedeemState::Redeeming { + redeem_amount: final_amount + } + } + } + .into() + })); + + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); +} + +#[test] +fn inbound_collect_redeem_order() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::RedeemCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_redeem_orders(investment_id( + pool_id, + default_tranche_id(pool_id) + ))); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Enable liquidity pool transferability + enable_liquidity_pool_transferability(currency_id); + + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify collected redemption was burned from investor + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount + } + .into())); + + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: amount, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign CollectedRedemptionTrancheTokens should be killed + assert!(!pallet_foreign_investments::CollectedRedemptionTrancheTokens::::contains_key( + investor.clone(), + default_investment_id(), + )); + + // Foreign RedemptionState should be killed + assert!(!pallet_foreign_investments::RedemptionState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Clearing of foreign RedeemState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + }); +} + +mod setup { + use super::*; + use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; + + /// Sets up required permissions for the investor and executes an + /// initial investment via LiquidityPools by executing + /// `IncreaseInvestOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand + pub fn do_initial_increase_investment( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let valid_until = DEFAULT_VALIDITY; + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + + // Should fail if investor does not have investor role yet + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + + // Make investor the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + investor.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + let amount_before = OrmlTokens::free_balance(currency_id, &default_investment_account()); + let final_amount = amount_before + .ensure_add(amount) + .expect("Should not overflow when incrementing amount"); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was transferred into investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + final_amount + ); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: InvestState::InvestmentOngoing { + invest_amount: final_amount + }, + } + .into() + })); + assert_eq!( + System::events().iter().last().unwrap().event, + pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor, + amount: final_amount + } + .into() + ); + } + + /// Sets up required permissions for the investor and executes an + /// initial redemption via LiquidityPools by executing + /// `IncreaseRedeemOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand. + /// + /// NOTE: Mints exactly the redeeming amount of tranche tokens. + pub fn do_initial_increase_redemption( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let valid_until = DEFAULT_VALIDITY; + + // Fund `DomainLocator` account of origination domain as redeemed tranche tokens + // are transferred from this account instead of minting + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount + )); + + // Verify redemption has not been made yet + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id: 42, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + + // Should fail if investor does not have investor role yet + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + + // Make investor the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + investor.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify redemption was transferred into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + amount + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) + ), + 0 + ); + assert_eq!( + System::events().iter().nth_back(4).unwrap().event, + pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: amount + } + }, + } + .into() + ); + assert_eq!( + System::events().iter().last().unwrap().event, + pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount + } + .into() + ); + + // Verify order id is 0 + assert_eq!( + pallet_investments::Pallet::::redeem_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + } +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs new file mode 100644 index 0000000000..de538b41a9 --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -0,0 +1,373 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +use cfg_primitives::{currency_decimals, Balance, Moment, PoolId, TrancheId}; +use cfg_traits::{investments::InvestmentAccountant, PoolMutate}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + pools::TrancheMetadata, + tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, +}; +use cumulus_primitives_core::Junction::GlobalConsensus; +use development_runtime::{ + LiquidityPools, LiquidityPoolsGateway, OrmlAssetRegistry, OrmlTokens, PoolSystem, + Runtime as DevelopmentRuntime, RuntimeOrigin, TreasuryPalletId, +}; +use frame_support::{ + assert_ok, + traits::{ + fungible::Mutate as _, + fungibles::{Balanced, Mutate}, + Get, PalletInfo, + }, +}; +use liquidity_pools_gateway_routers::{ + ethereum_xcm::EthereumXCMRouter, DomainRouter, XCMRouter, XcmDomain as GatewayXcmDomain, + XcmTransactInfo, +}; +use orml_asset_registry::{AssetMetadata, Metadata}; +use pallet_liquidity_pools::Message; +use pallet_pool_system::tranches::{TrancheInput, TrancheType}; +use runtime_common::{ + account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, +}; +use sp_core::H160; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, + BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, +}; +use xcm::{ + latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, + prelude::{Parachain, X1, X2}, + VersionedMultiLocation, +}; + +use crate::{ + chain::centrifuge::development, + liquidity_pools::pallet::development::{ + setup::{dollar, ALICE, BOB, PARA_ID_MOONBEAM}, + tests::register_ausd, + }, + utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, +}; + +pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; +pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); +pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; +pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, DEFAULT_EVM_ADDRESS_MOONBEAM); +pub const DEFAULT_VALIDITY: Moment = 2555583502; +pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); +pub const DEFAULT_POOL_ID: u64 = 42; +pub const DEFAULT_MOONBEAM_LOCATION: MultiLocation = MultiLocation { + parents: 1, + interior: X1(Parachain(PARA_ID_MOONBEAM)), +}; + +pub type LiquidityPoolMessage = Message; + +pub fn get_default_moonbeam_native_token_location() -> MultiLocation { + MultiLocation { + parents: 1, + interior: X2(Parachain(PARA_ID_MOONBEAM), general_key(&[0, 1])), + } +} + +pub fn set_test_domain_router( + evm_chain_id: u64, + xcm_domain_location: VersionedMultiLocation, + currency_id: CurrencyId, + fee_location: VersionedMultiLocation, +) { + let ethereum_xcm_router = EthereumXCMRouter:: { + router: XCMRouter { + xcm_domain: GatewayXcmDomain { + location: Box::new(xcm_domain_location), + ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), + contract_address: H160::from(DEFAULT_EVM_ADDRESS_MOONBEAM), + max_gas_limit: 700_000, + transact_info: XcmTransactInfo { + transact_extra_weight: 1.into(), + max_weight: 8_000_000_000_000_000.into(), + transact_extra_weight_signed: Some(3.into()), + }, + fee_currency: currency_id, + fee_per_second: default_per_second(18), + fee_asset_location: Box::new(fee_location), + }, + _marker: Default::default(), + }, + _marker: Default::default(), + }; + + let domain_router = DomainRouter::EthereumXCM(ethereum_xcm_router); + let domain = Domain::EVM(evm_chain_id); + + assert_ok!(LiquidityPoolsGateway::set_domain_router( + RuntimeOrigin::root(), + domain, + domain_router, + )); +} + +/// Initializes universally required storage for liquidityPools tests: +/// * Set the EthereumXCM router which in turn sets: +/// * transact info and domain router for Moonbeam `MultiLocation`, +/// * fee for GLMR (`GLIMMER_CURRENCY_ID`), +/// * Register GLMR and AUSD in `OrmlAssetRegistry`, +/// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice, Bob and the Treasury. +/// +/// NOTE: AUSD is the default pool currency in `create_pool`. +/// Neither AUSD nor GLMR are registered as a liquidityPools-transferable +/// currency! +pub fn setup_pre_requirements() { + /// Set the EthereumXCM router necessary for Moonbeam. + set_test_domain_router( + MOONBEAM_EVM_CHAIN_ID, + DEFAULT_MOONBEAM_LOCATION.into(), + GLIMMER_CURRENCY_ID, + get_default_moonbeam_native_token_location().into(), + ); + + /// Register Moonbeam's native token + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + asset_metadata( + "Glimmer".into(), + "GLMR".into(), + 18, + false, + Some(VersionedMultiLocation::V3( + get_default_moonbeam_native_token_location() + )), + CrossChainTransferability::Xcm(Default::default()), + ), + Some(GLIMMER_CURRENCY_ID) + )); + + // Give Alice, Bob and Treasury enough glimmer to pay for fees + OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &ALICE.into(), DEFAULT_BALANCE_GLMR); + OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &BOB.into(), DEFAULT_BALANCE_GLMR); + // Treasury pays for `Executed*` messages + OrmlTokens::deposit( + GLIMMER_CURRENCY_ID, + &TreasuryPalletId::get().into_account_truncating(), + DEFAULT_BALANCE_GLMR, + ); + + // Register AUSD in the asset registry which is the default pool currency in + // `create_pool` + register_ausd(); +} + +/// Creates a new pool for the given id with +/// * BOB as admin and depositor +/// * Two tranches +/// * AUSD as pool currency with max reserve 10k. +pub fn create_ausd_pool(pool_id: u64) { + create_currency_pool(pool_id, AUSD_CURRENCY_ID, dollar(currency_decimals::AUSD)) +} + +/// Creates a new pool for for the given id with the provided currency. +/// * BOB as admin and depositor +/// * Two tranches +/// * The given `currency` as pool currency with of `currency_decimals`. +pub fn create_currency_pool(pool_id: u64, currency_id: CurrencyId, currency_decimals: Balance) { + assert_ok!(PoolSystem::create( + BOB.into(), + BOB.into(), + pool_id, + vec![ + TrancheInput { + tranche_type: TrancheType::Residual, + seniority: None, + metadata: + TrancheMetadata { + // NOTE: For now, we have to set these metadata fields of the first tranche + // to be convertible to the 32-byte size expected by the liquidity pools + // AddTranche message. + token_name: BoundedVec::< + u8, + cfg_types::consts::pools::MaxTrancheNameLengthBytes, + >::try_from("A highly advanced tranche".as_bytes().to_vec()) + .expect(""), + token_symbol: BoundedVec::< + u8, + cfg_types::consts::pools::MaxTrancheSymbolLengthBytes, + >::try_from("TrNcH".as_bytes().to_vec()) + .expect(""), + } + }, + TrancheInput { + tranche_type: TrancheType::NonResidual { + interest_rate_per_sec: One::one(), + min_risk_buffer: Perquintill::from_percent(10), + }, + seniority: None, + metadata: TrancheMetadata { + token_name: BoundedVec::default(), + token_symbol: BoundedVec::default(), + } + } + ], + currency_id, + currency_decimals, + )); +} + +/// Returns a `VersionedMultiLocation` that can be converted into +/// `LiquidityPoolsWrappedToken` which is required for cross chain asset +/// registration and transfer. +pub fn liquidity_pools_transferable_multilocation( + chain_id: u64, + address: [u8; 20], +) -> VersionedMultiLocation { + VersionedMultiLocation::V3(MultiLocation { + parents: 0, + interior: X3( + PalletInstance( + ::PalletInfo::index::() + .expect("LiquidityPools should have pallet index") + .saturated_into(), + ), + GlobalConsensus(NetworkId::Ethereum { chain_id }), + AccountKey20 { + network: None, + key: address, + }, + ), + }) +} + +/// Enables `LiquidityPoolsTransferable` in the custom asset metadata for +/// the given currency_id. +/// +/// NOTE: Sets the location to the `MOONBEAM_EVM_CHAIN_ID` with dummy +/// address as the location is required for LiquidityPoolsWrappedToken +/// conversions. +pub fn enable_liquidity_pool_transferability(currency_id: CurrencyId) { + let metadata = + Metadata::::get(currency_id).expect("Currency should be registered"); + let location = Some(Some(liquidity_pools_transferable_multilocation( + MOONBEAM_EVM_CHAIN_ID, + // Value of evm_address is irrelevant here + [1u8; 20], + ))); + + assert_ok!(OrmlAssetRegistry::update_asset( + RuntimeOrigin::root(), + currency_id, + None, + None, + None, + None, + location, + Some(CustomMetadata { + // Changed: Allow liquidity_pools transferability + transferability: CrossChainTransferability::LiquidityPools, + ..metadata.additional + }) + )); +} + +/// Returns metadata for the given data with existential deposit of +/// 1_000_000. +pub fn asset_metadata( + name: Vec, + symbol: Vec, + decimals: u32, + is_pool_currency: bool, + location: Option, + transferability: CrossChainTransferability, +) -> AssetMetadata { + AssetMetadata { + name, + symbol, + decimals, + location, + existential_deposit: 1_000_000, + additional: CustomMetadata { + transferability, + mintable: false, + permissioned: false, + pool_currency: is_pool_currency, + }, + } +} + +pub(crate) mod investments { + use cfg_primitives::AccountId; + use cfg_traits::investments::TrancheCurrency as TrancheCurrencyT; + use cfg_types::investments::InvestmentAccount; + use development_runtime::PoolSystem; + use pallet_pool_system::tranches::TrancheLoc; + + use super::*; + + /// Returns the default investment account derived from the + /// `DEFAULT_POOL_ID` and its default tranche. + pub fn default_investment_account() -> AccountId { + InvestmentAccount { + investment_id: default_investment_id(), + } + .into_account_truncating() + } + + /// Returns the investment_id of the given pool and tranche ids. + pub fn investment_id( + pool_id: u64, + tranche_id: TrancheId, + ) -> cfg_types::tokens::TrancheCurrency { + ::TrancheCurrency::generate( + pool_id, tranche_id, + ) + } + + pub fn default_investment_id() -> cfg_types::tokens::TrancheCurrency { + ::TrancheCurrency::generate( + DEFAULT_POOL_ID, + default_tranche_id(DEFAULT_POOL_ID), + ) + } + + /// Returns the tranche id at index 0 for the given pool id. + pub fn default_tranche_id(pool_id: u64) -> TrancheId { + let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); + pool_details + .tranches + .tranche_id(TrancheLoc::Index(0)) + .expect("Tranche at index 0 exists") + } + + /// Returns the derived general currency index. + /// + /// Throws if the provided currency_id is not + /// `CurrencyId::ForeignAsset(id)`. + pub fn general_currency_index(currency_id: CurrencyId) -> u128 { + pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id) + .expect("ForeignAsset should convert into u128") + } +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs new file mode 100644 index 0000000000..2cbcbab67c --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -0,0 +1,488 @@ +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Centrifuge GmbH (centrifuge.io). +// This file is part of Centrifuge chain project. +// +// Centrifuge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version (see http://www.gnu.org/licenses). +// Centrifuge is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +use ::xcm::{ + latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, + prelude::{Parachain, X1, X2}, + VersionedMultiLocation, +}; +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; +use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + liquidity_pools::{Codec, InboundQueue}, + Permissions as _, PoolMutate, +}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + investments::{InvestCollection, InvestmentAccount, RedeemCollection}, + orders::FulfillmentWithPrice, + permissions::{PermissionScope, PoolRole, Role, UNION}, + pools::TrancheMetadata, + tokens::{ + CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, + ForeignAssetId, + }, + xcm::XcmMetadata, +}; +use codec::Encode; +use development_runtime::{ + Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, + OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, +}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Weight, + traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, +}; +use hex::FromHex; +use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; +use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; +use pallet_investments::CollectOutcome; +use pallet_liquidity_pools::{ + encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, +}; +use pallet_pool_system::{ + pool_types::PoolDetails, + tranches::{TrancheInput, TrancheLoc, TrancheType}, +}; +use runtime_common::{ + account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, +}; +use sp_core::H160; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, + BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, +}; +use xcm_emulator::TestExt; + +use crate::{ + liquidity_pools::pallet::development::{ + setup::{dollar, ALICE, BOB}, + test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::liquidity_pools::setup::{ + asset_metadata, create_ausd_pool, create_currency_pool, + enable_liquidity_pool_transferability, + investments::{ + default_investment_account, default_investment_id, default_tranche_id, + general_currency_index, investment_id, + }, + liquidity_pools_transferable_multilocation, set_test_domain_router, + setup_pre_requirements, DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, LiquidityPoolMessage, DEFAULT_BALANCE_GLMR, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + }, + }, + utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, +}; + +#[test] +fn transfer_non_tranche_tokens_from_local() { + TestNet::reset(); + + Development::execute_with(|| { + // Register GLMR and fund BOB + setup_pre_requirements(); + + let initial_balance = 100_000_000; + let amount = initial_balance / 2; + let dest_address = DEFAULT_DOMAIN_ADDRESS_MOONBEAM; + let currency_id = AUSD_CURRENCY_ID; + let source_account = BOB; + + // Mint sufficient balance + assert_ok!(OrmlTokens::mint_into( + currency_id, + &source_account.into(), + initial_balance + )); + assert_eq!( + OrmlTokens::free_balance(currency_id, &source_account.into()), + initial_balance + ); + + // Only `ForeignAsset` can be transferred + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.into()), + CurrencyId::Tranche(42u64, [0u8; 16]), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::InvalidTransferCurrency + ); + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.into()), + CurrencyId::Staking(cfg_types::tokens::StakingCurrency::BlockRewards), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.into()), + CurrencyId::Native, + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::AssetNotFound + ); + + // Cannot transfer as long as cross chain transferability is disabled + assert_noop!( + LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.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!( + LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.into()), + currency_id, + dest_address.clone(), + initial_balance.saturating_add(1), + ), + orml_tokens::Error::::BalanceTooLow + ); + + assert_ok!(LiquidityPools::transfer( + RuntimeOrigin::signed(source_account.into()), + currency_id, + dest_address.clone(), + amount, + )); + + // The account to which the currency should have been transferred + // to on Centrifuge for bookkeeping purposes. + let domain_account: AccountId = Domain::convert(dest_address.domain()); + // Verify that the correct amount of the token was transferred + // to the dest domain account on Centrifuge. + assert_eq!( + OrmlTokens::free_balance(currency_id, &domain_account), + amount + ); + assert_eq!( + OrmlTokens::free_balance(currency_id, &source_account.into()), + initial_balance - amount + ); + }); +} + +#[test] +fn transfer_non_tranche_tokens_to_local() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let initial_balance = DEFAULT_BALANCE_GLMR; + let amount = DEFAULT_BALANCE_GLMR / 2; + let dest_address = DEFAULT_DOMAIN_ADDRESS_MOONBEAM; + let currency_id = AUSD_CURRENCY_ID; + let receiver: AccountId = BOB.into(); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::Transfer { + currency: general_currency_index(currency_id), + // sender is irrelevant for other -> local + sender: ALICE, + receiver: receiver.clone().into(), + amount, + }; + + assert!(OrmlTokens::total_issuance(currency_id).is_zero()); + + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify that the correct amount was minted + assert_eq!(OrmlTokens::total_issuance(currency_id), amount); + assert_eq!(OrmlTokens::free_balance(currency_id, &receiver), amount); + + // Verify empty transfers throw + assert_noop!( + LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + LiquidityPoolMessage::Transfer { + currency: general_currency_index(currency_id), + sender: ALICE, + receiver: receiver.into(), + amount: 0, + }, + ), + pallet_liquidity_pools::Error::::InvalidTransferAmount + ); + }); +} + +#[test] +fn transfer_tranche_tokens_from_local() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000; + let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + let receiver = BOB; + + // Create the pool + create_ausd_pool(pool_id); + + let tranche_tokens: CurrencyId = + cfg_types::tokens::TrancheCurrency::generate(pool_id, default_tranche_id(pool_id)) + .into(); + + // Verify that we first need the destination address to be whitelisted + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + default_tranche_id(pool_id), + dest_address.clone(), + amount, + ), + pallet_liquidity_pools::Error::::UnauthorizedTransfer + ); + + // Make receiver the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + receiver.into(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); + + // Whitelist destination as TrancheInvestor of this Pool + let valid_until = u64::MAX; + assert_ok!(Permissions::add( + RuntimeOrigin::signed(receiver.into()), + Role::PoolRole(PoolRole::InvestorAdmin), + AccountConverter::::convert(dest_address.clone()), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + // Call the LiquidityPools::update_member which ensures the destination address + // is whitelisted. + assert_ok!(LiquidityPools::update_member( + RuntimeOrigin::signed(receiver.into()), + pool_id, + default_tranche_id(pool_id), + dest_address.clone(), + valid_until, + )); + + // Give receiver enough Tranche balance to be able to transfer it + OrmlTokens::deposit(tranche_tokens, &receiver.into(), amount); + + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!(LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(receiver.into()), + pool_id, + default_tranche_id(pool_id), + dest_address.clone(), + amount, + )); + + // The account to which the tranche should have been transferred + // to on Centrifuge for bookkeeping purposes. + let domain_account: AccountId = Domain::convert(dest_address.domain()); + + // Verify that the correct amount of the Tranche token was transferred + // to the dest domain account on Centrifuge. + assert_eq!( + OrmlTokens::free_balance(tranche_tokens, &domain_account), + amount + ); + assert!(OrmlTokens::free_balance(tranche_tokens, &receiver.into()).is_zero()); + }); +} + +#[test] +fn transfer_tranche_tokens_to_local() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + + // Create new pool + let pool_id = DEFAULT_POOL_ID; + create_ausd_pool(pool_id); + + let amount = 100_000_000; + let receiver: AccountId = BOB.into(); + let sender: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + let tranche_id = default_tranche_id(pool_id); + let tranche_tokens: CurrencyId = + cfg_types::tokens::TrancheCurrency::generate(pool_id, tranche_id).into(); + let valid_until = u64::MAX; + + // Fund `DomainLocator` account of origination domain tranche tokens are + // transferred from this account instead of minting + assert_ok!(OrmlTokens::mint_into( + tranche_tokens, + &sending_domain_locator, + amount + )); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::TransferTrancheTokens { + pool_id, + tranche_id, + sender: sender.address(), + domain: Domain::Centrifuge, + receiver: receiver.clone().into(), + amount, + }; + + // Verify that we first need the receiver to be whitelisted + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::UnauthorizedTransfer + ); + + // Make receiver the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + receiver.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); + + // Whitelist destination as TrancheInvestor of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::signed(receiver.clone()), + Role::PoolRole(PoolRole::InvestorAdmin), + receiver.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + // Finally, verify that we can now transfer the tranche to the destination + // address + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify that the correct amount of the Tranche token was transferred + // to the dest domain account on Centrifuge. + assert_eq!(OrmlTokens::free_balance(tranche_tokens, &receiver), amount); + assert!(OrmlTokens::free_balance(tranche_tokens, &sending_domain_locator).is_zero()); + }); +} + +#[test] +/// Try to transfer tranches for non-existing pools or invalid tranche ids for +/// existing pools. +fn transferring_invalid_tranche_tokens_should_fail() { + TestNet::reset(); + + Development::execute_with(|| { + setup_pre_requirements(); + let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); + + let valid_pool_id: u64 = 42; + create_ausd_pool(valid_pool_id); + let valid_tranche_id = default_tranche_id(valid_pool_id); + let valid_until = u64::MAX; + let transfer_amount = 42; + let invalid_pool_id = valid_pool_id + 1; + let invalid_tranche_id = valid_tranche_id.map(|i| i.saturating_add(1)); + assert!(PoolSystem::pool(invalid_pool_id).is_none()); + + // Make BOB the MembersListAdmin of both pools + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + BOB.into(), + PermissionScope::Pool(valid_pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + BOB.into(), + PermissionScope::Pool(invalid_pool_id), + Role::PoolRole(PoolRole::InvestorAdmin), + )); + + // Give BOB investor role for (valid_pool_id, invalid_tranche_id) and + // (invalid_pool_id, valid_tranche_id) + assert_ok!(Permissions::add( + RuntimeOrigin::signed(BOB.into()), + Role::PoolRole(PoolRole::InvestorAdmin), + AccountConverter::::convert(dest_address.clone()), + PermissionScope::Pool(invalid_pool_id), + Role::PoolRole(PoolRole::TrancheInvestor(valid_tranche_id, valid_until)), + )); + assert_ok!(Permissions::add( + RuntimeOrigin::signed(BOB.into()), + Role::PoolRole(PoolRole::InvestorAdmin), + AccountConverter::::convert(dest_address.clone()), + PermissionScope::Pool(valid_pool_id), + Role::PoolRole(PoolRole::TrancheInvestor(invalid_tranche_id, valid_until)), + )); + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(BOB.into()), + invalid_pool_id, + valid_tranche_id, + dest_address.clone(), + transfer_amount + ), + pallet_liquidity_pools::Error::::PoolNotFound + ); + assert_noop!( + LiquidityPools::transfer_tranche_tokens( + RuntimeOrigin::signed(BOB.into()), + valid_pool_id, + invalid_tranche_id, + dest_address, + transfer_amount + ), + pallet_liquidity_pools::Error::::TrancheNotFound + ); + }); +} From a3effb8b73c50a79cad7a3b7a93d5379582c352d Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 23 Aug 2023 13:05:06 +0200 Subject: [PATCH 51/96] tests: fix split imports --- .../tests/liquidity_pools/add_allow.rs | 59 ++++-------------- .../non_foreign_investments.rs | 41 +++---------- .../tests/liquidity_pools/setup.rs | 10 +-- .../tests/liquidity_pools/transfers.rs | 61 +++++-------------- 4 files changed, 43 insertions(+), 128 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs index 663a18b846..97a046a993 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs @@ -22,61 +22,32 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use ::xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - prelude::{Parachain, X1, X2}, - VersionedMultiLocation, -}; use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, - liquidity_pools::{Codec, InboundQueue}, - Permissions as _, PoolMutate, + liquidity_pools::InboundQueue, + Permissions as _, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, - fixed_point::Rate, - investments::{InvestCollection, InvestmentAccount, RedeemCollection}, - orders::FulfillmentWithPrice, - permissions::{PermissionScope, PoolRole, Role, UNION}, - pools::TrancheMetadata, + permissions::{PermissionScope, PoolRole, Role}, tokens::{ CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, ForeignAssetId, }, - xcm::XcmMetadata, }; -use codec::Encode; use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, - OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, -}; -use frame_support::{ - assert_noop, assert_ok, - dispatch::Weight, - traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, + LiquidityPools, OrmlAssetRegistry, Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, + System, }; -use hex::FromHex; -use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; +use frame_support::{assert_noop, assert_ok}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; -use pallet_investments::CollectOutcome; -use pallet_liquidity_pools::{ - encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, -}; -use pallet_pool_system::{ - pool_types::PoolDetails, - tranches::{TrancheInput, TrancheLoc, TrancheType}, -}; -use runtime_common::{ - account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, -}; -use sp_core::H160; +use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, - BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, + traits::{BadOrigin, Convert, One, Zero}, + BoundedVec, DispatchError, }; +use xcm::{latest::MultiLocation, VersionedMultiLocation}; use xcm_emulator::TestExt; use crate::{ @@ -85,13 +56,9 @@ use crate::{ test_net::{Development, Moonbeam, RelayChain, TestNet}, tests::liquidity_pools::setup::{ asset_metadata, create_ausd_pool, create_currency_pool, - enable_liquidity_pool_transferability, - investments::{ - default_investment_account, default_investment_id, default_tranche_id, - general_currency_index, investment_id, - }, - liquidity_pools_transferable_multilocation, set_test_domain_router, - setup_pre_requirements, DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, + enable_liquidity_pool_transferability, investments::default_tranche_id, + liquidity_pools_transferable_multilocation, setup_pre_requirements, DEFAULT_POOL_ID, + DEFAULT_VALIDITY, }, }, utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 531d2449aa..47265f891d 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -22,16 +22,10 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use ::xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - prelude::{Parachain, X1, X2}, - VersionedMultiLocation, -}; use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, - liquidity_pools::{Codec, InboundQueue}, - Permissions as _, PoolMutate, + liquidity_pools::InboundQueue, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, @@ -44,35 +38,19 @@ use cfg_types::{ CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, ForeignAssetId, }, - xcm::XcmMetadata, }; -use codec::Encode; use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, - OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, + Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, OrmlTokens, + Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, System, }; use frame_support::{ assert_noop, assert_ok, - dispatch::Weight, traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, }; -use hex::FromHex; -use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; use pallet_investments::CollectOutcome; -use pallet_liquidity_pools::{ - encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, -}; -use pallet_pool_system::{ - pool_types::PoolDetails, - tranches::{TrancheInput, TrancheLoc, TrancheType}, -}; -use runtime_common::{ - account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, -}; -use sp_core::H160; +use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, @@ -84,7 +62,9 @@ use crate::{ setup::{dollar, ALICE, BOB}, test_net::{Development, Moonbeam, RelayChain, TestNet}, tests::liquidity_pools::{ - non_foreign_investments::setup::{do_initial_increase_investment, do_initial_increase_redemption}, + non_foreign_investments::setup::{ + do_initial_increase_investment, do_initial_increase_redemption, + }, setup::{ asset_metadata, create_ausd_pool, create_currency_pool, enable_liquidity_pool_transferability, @@ -92,13 +72,12 @@ use crate::{ default_investment_account, default_investment_id, default_tranche_id, general_currency_index, investment_id, }, - liquidity_pools_transferable_multilocation, set_test_domain_router, setup_pre_requirements, LiquidityPoolMessage, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, + DEFAULT_POOL_ID, DEFAULT_VALIDITY, }, }, }, - utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, + utils::AUSD_CURRENCY_ID, }; #[test] @@ -873,7 +852,7 @@ mod setup { pallet_investments::Event::::RedeemOrderUpdated { investment_id: default_investment_id(), submitted_at: 0, - who: investor.clone(), + who: investor, amount } .into() diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs index de538b41a9..204a43d991 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -134,11 +134,11 @@ pub fn set_test_domain_router( } /// Initializes universally required storage for liquidityPools tests: -/// * Set the EthereumXCM router which in turn sets: -/// * transact info and domain router for Moonbeam `MultiLocation`, -/// * fee for GLMR (`GLIMMER_CURRENCY_ID`), -/// * Register GLMR and AUSD in `OrmlAssetRegistry`, -/// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice, Bob and the Treasury. +/// * Set the EthereumXCM router which in turn sets: +/// * transact info and domain router for Moonbeam `MultiLocation`, +/// * fee for GLMR (`GLIMMER_CURRENCY_ID`), +/// * Register GLMR and AUSD in `OrmlAssetRegistry`, +/// * Mint 10 GLMR (`DEFAULT_BALANCE_GLMR`) for Alice, Bob and the Treasury. /// /// NOTE: AUSD is the default pool currency in `create_pool`. /// Neither AUSD nor GLMR are registered as a liquidityPools-transferable diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs index 2cbcbab67c..ee064c5900 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -22,61 +22,32 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use ::xcm::{ - latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId}, - prelude::{Parachain, X1, X2}, - VersionedMultiLocation, -}; -use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; +use cfg_primitives::{AccountId, Balance, PoolId, TrancheId, CFG}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, - liquidity_pools::{Codec, InboundQueue}, - Permissions as _, PoolMutate, + liquidity_pools::InboundQueue, + Permissions as _, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, - fixed_point::Rate, - investments::{InvestCollection, InvestmentAccount, RedeemCollection}, - orders::FulfillmentWithPrice, - permissions::{PermissionScope, PoolRole, Role, UNION}, - pools::TrancheMetadata, + permissions::{PermissionScope, PoolRole, Role}, tokens::{ CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, ForeignAssetId, }, - xcm::XcmMetadata, }; -use codec::Encode; use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, LiquidityPoolsGateway, Loans, - OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, TreasuryPalletId, XTokens, XcmTransactor, -}; -use frame_support::{ - assert_noop, assert_ok, - dispatch::Weight, - traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, + LiquidityPools, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, }; -use hex::FromHex; -use liquidity_pools_gateway_routers::XcmDomain as GatewayXcmDomain; +use frame_support::{assert_noop, assert_ok, traits::fungibles::Mutate}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; -use pallet_investments::CollectOutcome; -use pallet_liquidity_pools::{ - encoded_contract_call, Error::UnauthorizedTransfer, Message, ParachainId, Router, XcmDomain, -}; -use pallet_pool_system::{ - pool_types::PoolDetails, - tranches::{TrancheInput, TrancheLoc, TrancheType}, -}; -use runtime_common::{ - account_conversion::AccountConverter, xcm::general_key, xcm_fees::default_per_second, -}; -use sp_core::H160; +use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, - BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, + traits::{Convert, One, Zero}, + BoundedVec, DispatchError, }; +use xcm::{latest::MultiLocation, VersionedMultiLocation}; use xcm_emulator::TestExt; use crate::{ @@ -86,12 +57,10 @@ use crate::{ tests::liquidity_pools::setup::{ asset_metadata, create_ausd_pool, create_currency_pool, enable_liquidity_pool_transferability, - investments::{ - default_investment_account, default_investment_id, default_tranche_id, - general_currency_index, investment_id, - }, - liquidity_pools_transferable_multilocation, set_test_domain_router, - setup_pre_requirements, DEFAULT_MOONBEAM_LOCATION, DEFAULT_POOL_ID, DEFAULT_VALIDITY, LiquidityPoolMessage, DEFAULT_BALANCE_GLMR, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + investments::{default_tranche_id, general_currency_index, investment_id}, + liquidity_pools_transferable_multilocation, setup_pre_requirements, + LiquidityPoolMessage, DEFAULT_BALANCE_GLMR, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + DEFAULT_POOL_ID, }, }, utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, From 96b5fbd049f4f2e38dd5e8bedce64650ad923875 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 24 Aug 2023 11:20:04 +0200 Subject: [PATCH 52/96] tests: add decrease underflow, require collect --- .../tests/liquidity_pools/add_allow.rs | 7 - .../non_foreign_investments.rs | 401 ++++++++++++++++-- .../tests/liquidity_pools/setup.rs | 12 +- .../tests/liquidity_pools/transfers.rs | 5 - runtime/integration-tests/src/utils/mod.rs | 2 +- 5 files changed, 381 insertions(+), 46 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs index 97a046a993..a6285773c9 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs @@ -78,7 +78,6 @@ use crate::{ #[test] fn add_pool() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; @@ -124,7 +123,6 @@ fn add_pool() { #[test] fn add_tranche() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); let decimals: u8 = 15; @@ -172,7 +170,6 @@ fn add_tranche() { #[test] fn update_member() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -253,7 +250,6 @@ fn update_member() { #[test] fn update_token_price() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); let decimals: u8 = 15; @@ -275,7 +271,6 @@ fn update_token_price() { #[test] fn add_currency() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -294,7 +289,6 @@ fn add_currency() { #[test] fn add_currency_should_fail() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -398,7 +392,6 @@ fn add_currency_should_fail() { #[test] fn allow_pool_currency() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 47265f891d..71f87f5aa2 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -83,10 +83,8 @@ use crate::{ #[test] fn inbound_increase_invest_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); @@ -113,16 +111,14 @@ fn inbound_increase_invest_order() { #[test] fn inbound_decrease_invest_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; + let invest_amount: u128 = 100_000_000; let decrease_amount = invest_amount / 3; let final_amount = invest_amount - decrease_amount; let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; + let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; // Create new pool @@ -187,10 +183,8 @@ fn inbound_decrease_invest_order() { #[test] fn inbound_cancel_invest_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; let investor: AccountId = BOB.into(); @@ -276,10 +270,8 @@ fn inbound_cancel_invest_order() { #[test] fn inbound_collect_invest_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); @@ -289,7 +281,6 @@ fn inbound_collect_invest_order() { // Create new pool create_currency_pool(pool_id, currency_id, currency_decimals.into()); - let investment_currency_id: CurrencyId = default_investment_id().into(); // Set permissions and execute initial investment @@ -299,10 +290,7 @@ fn inbound_collect_invest_order() { // Process and fulfill order // NOTE: Without this step, the order id is not cleared and // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_invest_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); + assert_ok!(Investments::process_invest_orders(default_investment_id())); // Tranche tokens will be minted upon fulfillment assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); @@ -403,10 +391,8 @@ fn inbound_collect_invest_order() { #[test] fn inbound_increase_redeem_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); @@ -427,16 +413,16 @@ fn inbound_increase_redeem_order() { .amount, amount ); + + // increase again, state should be SwapIntoForeignDone }); } #[test] fn inbound_decrease_redeem_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; let decrease_amount = redeem_amount / 3; @@ -487,13 +473,12 @@ fn inbound_decrease_redeem_order() { OrmlTokens::free_balance(default_investment_id().into(), &investor), 0 ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account assert_eq!( OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), decrease_amount ); + // Foreign RedemptionState should be updated assert!(System::events().iter().any(|e| { e.event == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { @@ -529,12 +514,97 @@ fn inbound_decrease_redeem_order() { } #[test] -fn inbound_collect_redeem_order() { +fn inbound_cancel_redeem_order() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); + + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::CancelRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + redeem_amount + ); + + // Foreign RedemptionState should be updated + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::Invested { invest_amount: redeem_amount }, + } + .into() + })); + + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); +} +#[test] +fn inbound_collect_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = BOB.into(); @@ -557,10 +627,7 @@ fn inbound_collect_redeem_order() { // Process and fulfill order // NOTE: Without this step, the order id is not cleared and // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_redeem_orders(investment_id( - pool_id, - default_tranche_id(pool_id) - ))); + assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), FulfillmentWithPrice:: { @@ -667,6 +734,286 @@ fn inbound_collect_redeem_order() { }); } +mod should_fail { + use pallet_foreign_investments::errors::{InvestError, RedeemError}; + + use super::*; + + mod decrease_should_underflow { + use super::*; + + #[test] + fn invest_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let decrease_amount = invest_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability(currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::Decrease + ) + ); + }); + } + + #[test] + fn redeem_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount: u128 = 100_000_000; + let decrease_amount = redeem_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption( + pool_id, + redeem_amount, + investor.clone(), + currency_id, + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::Decrease + ) + ); + }); + } + } + + mod should_throw_requires_collect { + use super::*; + #[test] + fn invest_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + }); + } + + #[test] + fn redeem_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Mint more into DomainLocator required for subsequent invest attempt + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + 1, + )); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + }); + } + } + + mod mismatching_currencies { + use super::*; + use crate::utils::GLMR_CURRENCY_ID; + + #[test] + fn invest_increase_another_currency() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = GLMR_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + pool_currency, + ); + enable_liquidity_pool_transferability(pool_currency); + + // Should fail to increase in another currency + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_liquidity_pools::Error::::InvalidInvestCurrency + ); + + // TODO: Add foreign currency to accepted payment + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::Increase + ) + ); + + // Should fail to decrease in another currency + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::Decrease + ) + ); + }); + } + + // TODO: Similar tests for decreasing investments, increase/decrease and + // collect redemption + } +} + mod setup { use super::*; use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs index 204a43d991..b5abba27c3 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -70,7 +70,7 @@ use crate::{ setup::{dollar, ALICE, BOB, PARA_ID_MOONBEAM}, tests::register_ausd, }, - utils::{AUSD_CURRENCY_ID, GLIMMER_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, + utils::{AUSD_CURRENCY_ID, GLMR_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, }; pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; @@ -148,7 +148,7 @@ pub fn setup_pre_requirements() { set_test_domain_router( MOONBEAM_EVM_CHAIN_ID, DEFAULT_MOONBEAM_LOCATION.into(), - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, get_default_moonbeam_native_token_location().into(), ); @@ -165,15 +165,15 @@ pub fn setup_pre_requirements() { )), CrossChainTransferability::Xcm(Default::default()), ), - Some(GLIMMER_CURRENCY_ID) + Some(GLMR_CURRENCY_ID) )); // Give Alice, Bob and Treasury enough glimmer to pay for fees - OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &ALICE.into(), DEFAULT_BALANCE_GLMR); - OrmlTokens::deposit(GLIMMER_CURRENCY_ID, &BOB.into(), DEFAULT_BALANCE_GLMR); + OrmlTokens::deposit(GLMR_CURRENCY_ID, &ALICE.into(), DEFAULT_BALANCE_GLMR); + OrmlTokens::deposit(GLMR_CURRENCY_ID, &BOB.into(), DEFAULT_BALANCE_GLMR); // Treasury pays for `Executed*` messages OrmlTokens::deposit( - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, &TreasuryPalletId::get().into_account_truncating(), DEFAULT_BALANCE_GLMR, ); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs index ee064c5900..d0a3c29919 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -69,7 +69,6 @@ use crate::{ #[test] fn transfer_non_tranche_tokens_from_local() { TestNet::reset(); - Development::execute_with(|| { // Register GLMR and fund BOB setup_pre_requirements(); @@ -171,7 +170,6 @@ fn transfer_non_tranche_tokens_from_local() { #[test] fn transfer_non_tranche_tokens_to_local() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -219,7 +217,6 @@ fn transfer_non_tranche_tokens_to_local() { #[test] fn transfer_tranche_tokens_from_local() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -309,7 +306,6 @@ fn transfer_tranche_tokens_from_local() { #[test] fn transfer_tranche_tokens_to_local() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); @@ -387,7 +383,6 @@ fn transfer_tranche_tokens_to_local() { /// existing pools. fn transferring_invalid_tranche_tokens_should_fail() { TestNet::reset(); - Development::execute_with(|| { setup_pre_requirements(); let dest_address: DomainAddress = DomainAddress::EVM(1284, [99; 20]); diff --git a/runtime/integration-tests/src/utils/mod.rs b/runtime/integration-tests/src/utils/mod.rs index 3d5aa36e4e..1d3ea32f94 100644 --- a/runtime/integration-tests/src/utils/mod.rs +++ b/runtime/integration-tests/src/utils/mod.rs @@ -30,7 +30,7 @@ pub mod tokens; /// The relay native token's asset id pub const RELAY_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1); /// The Glimmer asset id -pub const GLIMMER_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1000); +pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1000); /// The AUSD asset id pub const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2000); /// The EVM Chain id of Moonbeam From 9d3d04157fea4a0f89c77905436fcfdfc53758b4 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 24 Aug 2023 11:22:39 +0200 Subject: [PATCH 53/96] feat: impl requires_collect --- libs/traits/src/investments.rs | 18 +++++- pallets/foreign-investments/src/errors.rs | 4 ++ pallets/foreign-investments/src/impls/mod.rs | 61 +++++++++---------- .../foreign-investments/src/impls/redeem.rs | 2 +- pallets/investments/src/lib.rs | 24 ++++++++ pallets/liquidity-pools/src/hooks.rs | 19 ------ pallets/liquidity-pools/src/inbound.rs | 6 +- 7 files changed, 75 insertions(+), 59 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 049ead7718..5d572c2406 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -85,6 +85,20 @@ pub trait Investment { who: &AccountId, investment_id: Self::InvestmentId, ) -> Result; + + /// Checks whether an investment requires to be collected before it can be + /// updated. + /// + /// NOTE: Returns false if the investment does not exist. + fn investment_requires_collect(investor: &AccountId, investment_id: Self::InvestmentId) + -> bool; + + /// Checks whether a redemption requires to be collected before it can be + /// further updated. + /// + /// NOTE: Returns false if the redemption does not exist. + fn redemption_requires_collect(investor: &AccountId, investment_id: Self::InvestmentId) + -> bool; } /// A trait which allows to collect existing investments and redemptions. @@ -190,14 +204,14 @@ pub trait InvestmentAccountant { amount: Self::Amount, ) -> Result<(), Self::Error>; - /// Increases the existance of + /// Increases the existence of fn deposit( buyer: &AccountId, id: Self::InvestmentId, amount: Self::Amount, ) -> Result<(), Self::Error>; - /// Reduce the existance of an asset + /// Reduce the existence of an asset fn withdraw( seller: &AccountId, id: Self::InvestmentId, diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index 619163e15a..8ba006ab27 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -26,6 +26,8 @@ pub enum InvestError { /// Failed to transition a (partially) processed investment after /// collecting. Collect, + /// The investment needs to be collected before it can be updated further. + CollectRequired, } #[derive(Encode, Decode, TypeInfo, PalletError)] @@ -42,4 +44,6 @@ pub enum RedeemError { /// Failed to transition a (partially) processed redemption after an epoch /// was executed. EpochExecution, + /// The redemption needs to be collected before it can be updated further. + CollectRequired, } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index b425f40bdd..7056780782 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -97,16 +97,13 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - let pre_state = InvestmentState::::get(who, investment_id); - - // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be - // removed before deploying to production - let unprocessed_invest_amount = T::Investment::investment(who, investment_id)?; + // TODO(future): Add implicit collection or error handling (i.e. message to + // source domain) ensure!( - unprocessed_invest_amount == pre_state.get_investing_amount(), - DispatchError::Corruption + !T::Investment::investment_requires_collect(who, investment_id), + Error::::InvestError(InvestError::CollectRequired) ); - + let pre_state = InvestmentState::::get(who, investment_id); let post_state = pre_state .transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, @@ -131,14 +128,17 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + // TODO(future): Add implicit collection or error handling (i.e. message to + // source domain) + ensure!( + !T::Investment::investment_requires_collect(who, investment_id), + Error::::InvestError(InvestError::CollectRequired) + ); let pre_state = InvestmentState::::get(who, investment_id); - // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be - // removed before deploying to production - let unprocessed_invest_amount = T::Investment::investment(who, investment_id)?; ensure!( - unprocessed_invest_amount == pre_state.get_investing_amount(), - DispatchError::Corruption + pre_state.get_investing_amount() >= amount, + Error::::InvestError(InvestError::Decrease) ); let post_state = pre_state @@ -152,10 +152,6 @@ impl ForeignInvestment for Pallet { log::debug!("InvestState transition error: {:?}", e); Error::::from(InvestError::Decrease) })?; - #[cfg(feature = "std")] - { - dbg!(pre_state, post_state); - } Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; Ok(()) @@ -167,17 +163,15 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result<(), DispatchError> { - let pre_state = - RedemptionState::::get(who, investment_id).increase_invested_amount(amount)?; - - // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be - // removed before deploying to production - let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id)?; + // TODO(future): Add implicit collection or error handling (i.e. message to + // source domain) ensure!( - unprocessed_redeem_amount == pre_state.get_redeeming_amount(), - DispatchError::Corruption + !T::Investment::redemption_requires_collect(who, investment_id), + Error::::RedeemError(RedeemError::CollectRequired) ); + let pre_state = + RedemptionState::::get(who, investment_id).increase_invested_amount(amount)?; let post_state = pre_state .transition(RedeemTransition::IncreaseRedeemOrder(amount)) .map_err(|e| { @@ -196,19 +190,20 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, ) -> Result { - let pre_state = RedemptionState::::get(who, investment_id); - - // NOTE: This adds one db read but let's be safe for the MVP, can hopefully be - // removed before deploying to production - let unprocessed_redeem_amount = T::Investment::redemption(who, investment_id)?; + // TODO(future): Add implicit collection or error handling (i.e. message to + // source domain) ensure!( - unprocessed_redeem_amount == pre_state.get_redeeming_amount(), - DispatchError::Corruption + !T::Investment::redemption_requires_collect(who, investment_id), + Error::::RedeemError(RedeemError::CollectRequired) ); + let pre_state = RedemptionState::::get(who, investment_id); let post_state = pre_state .transition(RedeemTransition::DecreaseRedeemOrder(amount)) - .map_err(|_| Error::::from(RedeemError::Decrease))?; + .map_err(|e| { + log::debug!("RedeemState transition error: {:?}", e); + Error::::from(RedeemError::Decrease) + })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; Ok(amount) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 4498c4d178..c8ae18a18d 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -762,7 +762,7 @@ where match self.get_redeeming_amount() { amount if amount.is_zero() => error_not_redeeming, // Can only decrease up to current redeeming amount - redeem_amount if redeem_amount <= amount => { + redeem_amount if redeem_amount < amount => { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } // Entire redeeming amount becomes invested amount, i.e. remove `Redeeming` from inner diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 52e07307ed..07b630c792 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -1148,6 +1148,30 @@ where Ok(RedeemOrders::::get(who, investment_id) .map_or_else(Zero::zero, |order| order.amount())) } + + fn investment_requires_collect( + investor: &T::AccountId, + investment_id: Self::InvestmentId, + ) -> bool { + InvestOrders::::get(investor, investment_id) + .map(|order| { + let cur_order_id = InvestOrderId::::get(investment_id); + order.submitted_at() != cur_order_id + }) + .unwrap_or(false) + } + + fn redemption_requires_collect( + investor: &T::AccountId, + investment_id: Self::InvestmentId, + ) -> bool { + RedeemOrders::::get(investor, investment_id) + .map(|order| { + let cur_order_id = RedeemOrderId::::get(investment_id); + order.submitted_at() != cur_order_id + }) + .unwrap_or(false) + } } impl OrderManager for Pallet diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index e637f6e2db..5907223b8d 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -54,16 +54,7 @@ where let wrapped_token = Pallet::::try_get_wrapped_token(&status.foreign_currency)?; let domain_address: DomainAddress = wrapped_token.into(); - #[cfg(feature = "std")] - { - println!("Before burning"); - dbg!(status.clone()); - } T::Tokens::burn_from(status.foreign_currency, &investor, status.amount_decreased)?; - #[cfg(feature = "std")] - { - println!("After burning"); - } let message: MessageOf = Message::ExecutedDecreaseInvestOrder { pool_id: investment_id.of_pool(), @@ -72,18 +63,8 @@ where currency, currency_payout: status.amount_decreased, }; - #[cfg(feature = "std")] - { - dbg!(message.clone()); - } - T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; - #[cfg(feature = "std")] - { - println!("After submitting"); - } - Ok(()) } } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 910385f8ce..0547375c9a 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -170,10 +170,7 @@ where ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let amount = T::ForeignInvestment::investment(&investor, invest_id)?; - #[cfg(feature = "std")] - { - dbg!(amount); - } + Self::handle_decrease_invest_order(pool_id, tranche_id, investor, currency_index, amount) } @@ -270,6 +267,7 @@ where ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let amount = T::ForeignInvestment::redemption(&investor, invest_id)?; + Self::handle_decrease_redeem_order( pool_id, tranche_id, From 7a18f6e3f79c96610f1ffbf0bdaff1ee3c36c063 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 24 Aug 2023 15:20:25 +0200 Subject: [PATCH 54/96] wip: redemption currency checks, payment/payout checks --- libs/traits/src/investments.rs | 74 ++++++++++--------- pallets/foreign-investments/src/impls/mod.rs | 48 ++++++++++-- pallets/foreign-investments/src/lib.rs | 22 ++++++ pallets/liquidity-pools/src/inbound.rs | 22 ++++-- pallets/liquidity-pools/src/lib.rs | 35 ++++++--- .../tests/liquidity_pools/add_allow.rs | 2 +- .../non_foreign_investments.rs | 2 +- 7 files changed, 149 insertions(+), 56 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 5d572c2406..52980a57a9 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -47,11 +47,11 @@ pub trait Investment { currency: Self::CurrencyId, ) -> bool; - /// Returns, if possible, the current investment amount (in pool currency) - /// of who into the given investment class. + /// Returns, if possible, the currently unprocessed investment amount (in + /// pool currency) of who into the given investment class. /// - /// NOTE: Does NOT include any (partially) processed investment from pool - /// currency into tranche tokens. + /// NOTE: If the investment was (partially) processed, the unprocessed + /// amount is only updated upon collecting. fn investment( who: &AccountId, investment_id: Self::InvestmentId, @@ -76,11 +76,11 @@ pub trait Investment { currency: Self::CurrencyId, ) -> bool; - /// Returns, if possible, the current redemption amount (in tranche tokens) - /// of who into the given investment class. + /// Returns, if possible, the currently unprocessed redemption amount (in + /// tranche tokens) of who into the given investment class. /// - /// NOTE: Does NOT include any (partially) processed redemption from tranche - /// tokens into pool currency. + /// NOTE: If the redemption was (partially) processed, the unprocessed + /// amount is only updated upon collecting. fn redemption( who: &AccountId, investment_id: Self::InvestmentId, @@ -89,14 +89,14 @@ pub trait Investment { /// Checks whether an investment requires to be collected before it can be /// updated. /// - /// NOTE: Returns false if the investment does not exist. + /// NOTE: Defaults to false if the investment does not exist. fn investment_requires_collect(investor: &AccountId, investment_id: Self::InvestmentId) -> bool; /// Checks whether a redemption requires to be collected before it can be /// further updated. /// - /// NOTE: Returns false if the redemption does not exist. + /// NOTE: Defaults to false if the redemption does not exist. fn redemption_requires_collect(investor: &AccountId, investment_id: Self::InvestmentId) -> bool; } @@ -300,8 +300,8 @@ pub trait ForeignInvestment { type CollectInvestResult; /// Initiates the increment of a foreign investment amount in - /// `foreign_currency` of who into the investment class `pool_currency` to - /// amount. + /// `foreign_payment_currency` of who into the investment class + /// `pool_currency` to amount. /// /// NOTE: In general, we can assume that the foreign and pool currencies /// mismatch and that swapping one into the other happens asynchronously. In @@ -311,13 +311,13 @@ pub trait ForeignInvestment { who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, - foreign_currency: Self::CurrencyId, + foreign_payment_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; /// Initiates the decrement of a foreign investment amount in - /// `foreign_currency` of who into the investment class `pool_currency` to - /// amount. + /// `foreign_payment_currency` of who into the investment class + /// `pool_currency` to amount. /// /// NOTE: In general, we can assume that the foreign and pool currencies /// mismatch and that swapping one into the other happens asynchronously. In @@ -327,30 +327,35 @@ pub trait ForeignInvestment { who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, - foreign_currency: Self::CurrencyId, + foreign_payment_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; - /// Initiates the increment of a foreign redemption amount from - /// `pool_currency` of who into `foreign_currency` to amount. + /// Initiates the increment of a foreign redemption amount for the given + /// investment id. /// - /// NOTE: The incrementing redemption amount is bound by the processed - /// investment amount. + /// NOTE: The `foreign_payout_currency` is only required to ensure + /// subsequent redemption updating calls match to the original chosen + /// `foreign_payment_currency`. fn increase_foreign_redemption( who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, + foreign_payout_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; - /// Initiates the decrement of a foreign redemption amount from - /// `pool_currency` of who into `foreign_currency` to amount. + /// Initiates the decrement of a foreign redemption amount. /// - /// NOTE: The decrementing redemption amount is bound by the previously - /// incremented redemption amount. + /// NOTES: + /// * The decrementing redemption amount is bound by the previously + /// incremented redemption amount. + /// * The `foreign_payout_currency` is only required for the potential + /// dispatch of a response message. fn decrease_foreign_redemption( who: &AccountId, investment_id: Self::InvestmentId, amount: Self::Amount, + foreign_payout_currency: Self::CurrencyId, ) -> Result; /// Collect the results of a user's foreign invest orders for the given @@ -368,29 +373,30 @@ pub trait ForeignInvestment { /// appended to the next active order for this investment. /// /// NOTE: The currency of the collected amount will be `pool_currency` - /// whereas the user eventually wants to receive it in `foreign_currency`. + /// whereas the user eventually wants to receive it in + /// `foreign_payout_currency`. fn collect_foreign_redemption( who: &AccountId, investment_id: Self::InvestmentId, - foreign_currency: Self::CurrencyId, + foreign_payout_currency: Self::CurrencyId, pool_currency: Self::CurrencyId, ) -> Result<(), Self::Error>; - /// Returns, if possible, the current investment amount (in pool currency) - /// of who into the given investment class. + /// Returns, if possible, the currently unprocessed investment amount (in + /// pool currency) of who into the given investment class. /// - /// NOTE: Does NOT include any (partially) processed investment from pool - /// currency into tranche tokens. + /// NOTE: If the investment was (partially) processed, the unprocessed + /// amount is only updated upon collecting. fn investment( who: &AccountId, investment_id: Self::InvestmentId, ) -> Result; - /// Returns, if possible, the current redemption amount (in tranche tokens) - /// of who into the given investment class. + /// Returns, if possible, the currently unprocessed redemption amount (in + /// tranche tokens) of who into the given investment class. /// - /// NOTE: Does NOT include any (partially) processed redemption from tranche - /// tokens into pool currency. + /// NOTE: If the redemption was (partially) processed, the unprocessed + /// amount is only updated upon collecting. fn redemption( who: &AccountId, investment_id: Self::InvestmentId, diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 7056780782..94d8ea9fa0 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -33,7 +33,8 @@ use crate::{ TokenSwapReason, }, CollectedRedemptionTrancheTokens, Config, Error, Event, ForeignInvestmentInfo, - ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionState, SwapOf, TokenSwapOrderIds, + ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionPayoutCurrency, RedemptionState, + SwapOf, TokenSwapOrderIds, }; mod invest; @@ -162,7 +163,23 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, amount: T::Balance, + payout_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + // TODO(future): This error needs to be communicated to sending domain as it + // cannot be resolved by triggering a bot + let currency_matches = + RedemptionPayoutCurrency::::mutate(who, investment_id, |maybe_currency| { + if let Some(currency) = maybe_currency { + currency == &payout_currency + } else { + *maybe_currency = Some(payout_currency); + true + } + }); + ensure!( + currency_matches, + Error::::InvalidRedemptionPayoutCurrency + ); // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( @@ -189,7 +206,19 @@ impl ForeignInvestment for Pallet { who: &T::AccountId, investment_id: T::InvestmentId, amount: T::Balance, + payout_currency: T::CurrencyId, ) -> Result { + // TODO(future): This error needs to be communicated to sending domain as it + // cannot be resolved by triggering a bot + ensure!( + RedemptionPayoutCurrency::::get(who, investment_id) + .map(|currency| currency == payout_currency) + .unwrap_or_else(|| { + log::debug!("Redemption payout currency missing when calling decrease. Should never occur if redemption has been increased beforehand"); + false + }), + Error::::InvalidRedemptionPayoutCurrency + ); // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( @@ -213,7 +242,7 @@ impl ForeignInvestment for Pallet { fn collect_foreign_investment( who: &T::AccountId, investment_id: T::InvestmentId, - foreign_currency: T::CurrencyId, + foreign_payout_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result, DispatchError> { // No need to transition or update state as collection of tranche tokens is @@ -238,7 +267,7 @@ impl ForeignInvestment for Pallet { let amount_currency_payout = T::CurrencyConverter::stable_to_stable( pool_currency, amount_payment, - foreign_currency, + foreign_payout_currency, )?; Ok(ExecutedForeignCollectInvest { @@ -251,9 +280,18 @@ impl ForeignInvestment for Pallet { fn collect_foreign_redemption( who: &T::AccountId, investment_id: T::InvestmentId, - foreign_currency: T::CurrencyId, + foreign_payout_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + ensure!( + RedemptionPayoutCurrency::::get(who, investment_id) + .map(|currency| currency == foreign_payout_currency) + .unwrap_or_else(|| { + log::debug!("Redemption payout currency missing when calling decrease. Should never occur if redemption has been increased beforehand"); + false + }), + Error::::InvalidRedemptionPayoutCurrency + ); let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; CollectedRedemptionTrancheTokens::::try_mutate(who, investment_id, |amount| { amount.ensure_add_assign(collected.amount_payment)?; @@ -269,7 +307,7 @@ impl ForeignInvestment for Pallet { amount_unprocessed_redemption, SwapOf:: { amount: collected.amount_collected, - currency_in: foreign_currency, + currency_in: foreign_payout_currency, currency_out: pool_currency, }, )) diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 7072ddd787..4ff00aae7c 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -281,6 +281,20 @@ pub mod pallet { ValueQuery, >; + /// Maps an investor and their investment id to the foreign payout currency + /// requested on the initial redemption increment. + /// + /// NOTE: The lifetime of this storage mirrors the one of `RedemptionState`. + #[pallet::storage] + pub type RedemptionPayoutCurrency = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, + T::CurrencyId, + >; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -310,6 +324,12 @@ pub mod pallet { /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. InvestmentInfoNotFound, + /// The provided currency does not match the one provided when the first + /// redemption increase was triggered. + /// + /// NOTE: As long as the `RedemptionState` has not been cleared, the + /// payout currency cannot change from the initially provided one. + InvalidRedemptionPayoutCurrency, /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. TokenSwapReasonNotFound, @@ -330,4 +350,6 @@ pub mod pallet { Error::::RedeemError(error) } } + + // TODO: Add call to allow payment currency } diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 0547375c9a..e6df2e6e6d 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -187,9 +187,11 @@ where tranche_id: T::TrancheId, investor: T::AccountId, amount: ::Balance, + currency_index: GeneralCurrencyIndexOf, sending_domain: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; // Transfer tranche tokens from `DomainLocator` account of // origination domain @@ -202,7 +204,12 @@ where false, )?; - T::ForeignInvestment::increase_foreign_redemption(&investor, invest_id, amount)?; + T::ForeignInvestment::increase_foreign_redemption( + &investor, + invest_id, + amount, + payout_currency, + )?; Ok(()) } @@ -219,17 +226,20 @@ where pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - currency_index: GeneralCurrencyIndexOf, amount: ::Balance, + currency_index: GeneralCurrencyIndexOf, destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; + let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; + // TODO(@review): This is exactly `amount` as we can only decrement up to the // unprocessed redemption let tranche_tokens_payout = T::ForeignInvestment::decrease_foreign_redemption( &investor, invest_id.clone(), amount, + payout_currency, )?; T::Tokens::transfer( @@ -298,7 +308,7 @@ where ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; let currency_index_u128 = currency_index.index; - let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let payout_currency = Self::try_get_payout_currency(invest_id.clone(), currency_index)?; let pool_currency = T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; @@ -308,7 +318,7 @@ where } = T::ForeignInvestment::collect_foreign_investment( &investor, invest_id.clone(), - payment_currency, + payout_currency, pool_currency, )?; @@ -352,14 +362,14 @@ where currency_index: GeneralCurrencyIndexOf, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let payment_currency = Self::try_get_payment_currency(invest_id.clone(), currency_index)?; + let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; let pool_currency = T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; T::ForeignInvestment::collect_foreign_redemption( &investor, invest_id, - payment_currency, + payout_currency, pool_currency, )?; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 3a0866096c..d5375c14b8 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -313,9 +313,12 @@ pub mod pallet { InvalidDomain, /// The validity is in the past. InvalidTrancheInvestorValidity, - /// Failed to match the provided GeneralCurrencyIndex against the - /// investment currency of the pool. - InvalidInvestCurrency, + /// The derived currency from the provided GeneralCurrencyIndex is not + /// accepted as payment for the given pool. + InvalidPaymentCurrency, + /// The derived currency from the provided GeneralCurrencyIndex is not + /// accepted as payout for the given pool. + InvalidPayoutCurrency, /// The currency is not allowed to be transferred via LiquidityPools. InvalidTransferCurrency, /// The account derived from the [Domain] and [DomainAddress] has not @@ -668,7 +671,7 @@ pub mod pallet { let invest_id = Self::derive_invest_id(pool_id, tranche_id)?; ensure!( T::ForeignInvestment::accepted_payment_currency(invest_id, currency_id), - Error::::InvalidInvestCurrency + Error::::InvalidPaymentCurrency ); // Ensure the currency is enabled as pool_currency @@ -833,8 +836,9 @@ pub mod pallet { Ok(TrancheCurrency::generate(pool_id, tranche_id)) } - /// Ensures that the payment currency of the given investment id matches - /// the derived currency and returns the latter. + /// Ensures that currency id can be derived from the + /// GeneralCurrencyIndex and that the former is an accepted payment + /// currency for the given investment id. pub fn try_get_payment_currency( invest_id: ::TrancheCurrency, currency_index: GeneralCurrencyIndexOf, @@ -844,11 +848,23 @@ pub mod pallet { ensure!( T::ForeignInvestment::accepted_payment_currency(invest_id, currency), - Error::::InvalidInvestCurrency + Error::::InvalidPaymentCurrency ); Ok(currency) } + + /// Ensures that currency id can be derived from the + /// GeneralCurrencyIndex and that the former is an accepted payout + /// currency for the given investment id. + /// + /// NOTE: Exactly the same as try_get_payment_currency for now. + pub fn try_get_payout_currency( + invest_id: ::TrancheCurrency, + currency_index: GeneralCurrencyIndexOf, + ) -> Result, DispatchError> { + Self::try_get_payment_currency(invest_id, currency_index) + } } impl InboundQueue for Pallet @@ -911,12 +927,13 @@ pub mod pallet { tranche_id, investor, amount, - .. + currency, } => Self::handle_increase_redeem_order( pool_id, tranche_id, investor.into(), amount, + currency.into(), sender, ), Message::DecreaseRedeemOrder { @@ -929,8 +946,8 @@ pub mod pallet { pool_id, tranche_id, investor.into(), - currency.into(), amount, + currency.into(), sender, ), Message::CollectInvest { diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs index a6285773c9..afffb4dd32 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs @@ -482,7 +482,7 @@ fn allow_pool_should_fail() { default_tranche_id(pool_id), ausd_currency_id, ), - pallet_liquidity_pools::Error::::InvalidInvestCurrency + pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); // Should fail if currency is not liquidityPools transferable diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 71f87f5aa2..105b3c54d8 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -980,7 +980,7 @@ mod should_fail { }; assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_liquidity_pools::Error::::InvalidInvestCurrency + pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); // TODO: Add foreign currency to accepted payment From bdf467ca75dbe8833498a06667cea8bfd869b55d Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 24 Aug 2023 15:30:12 +0200 Subject: [PATCH 55/96] wip --- .github/workflows/build.yml | 4 + Cargo.lock | 5 +- libs/primitives/src/conversion.rs | 42 +- libs/traits/src/lib.rs | 68 +- libs/types/src/ids.rs | 1 + pallets/block-rewards/src/mock.rs | 16 +- pallets/liquidity-rewards/src/lib.rs | 2 +- pallets/order-book/Cargo.toml | 34 +- pallets/order-book/src/benchmarking.rs | 80 +- pallets/order-book/src/lib.rs | 433 ++++----- pallets/order-book/src/mock.rs | 130 ++- pallets/order-book/src/tests.rs | 822 +++++++++++------- pallets/order-book/src/weights.rs | 9 +- pallets/rewards/src/lib.rs | 22 +- runtime/altair/Cargo.toml | 6 +- runtime/altair/src/lib.rs | 108 ++- runtime/altair/src/migrations.rs | 29 +- runtime/altair/src/weights/mod.rs | 1 + .../src/weights/pallet_liquidity_rewards.rs | 37 + runtime/centrifuge/src/lib.rs | 187 ++-- runtime/common/src/migrations/nuke.rs | 18 +- runtime/development/src/lib.rs | 43 +- .../src/weights/pallet_order_book.rs | 93 +- src/chain_spec.rs | 21 +- 24 files changed, 1350 insertions(+), 861 deletions(-) create mode 100644 runtime/altair/src/weights/pallet_liquidity_rewards.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b422be4141..a01782f0a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,6 +72,10 @@ jobs: name: Publish to GCS run: | gsutil cp ./runtime/altair/target/srtool/release/wbuild/altair-runtime/altair_runtime.compact.compressed.wasm gs://centrifuge-artifact-releases/test-parachain/altair_runtime-$(git rev-parse --short HEAD).compact.compressed.wasm + - if: ${{ matrix.target == 'build-runtime-testnet' && matrix.package == 'altair-runtime' }} + name: Publish to GCS + run: | + gsutil cp ./runtime/altair/target/srtool/release/wbuild/altair-runtime/altair_runtime.compact.compressed.wasm gs://centrifuge-artifact-releases/parachain/algol-$(git rev-parse --short HEAD).compact.compressed.wasm - if: ${{ matrix.target == 'build-runtime' && matrix.package == 'centrifuge-runtime' }} name: Publish to GCS run: | diff --git a/Cargo.lock b/Cargo.lock index cde53f06b3..31d0fff36a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,7 +190,7 @@ dependencies = [ [[package]] name = "altair-runtime" -version = "0.10.28" +version = "0.10.30" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", @@ -252,6 +252,7 @@ dependencies = [ "pallet-keystore", "pallet-liquidity-pools", "pallet-liquidity-pools-gateway", + "pallet-liquidity-rewards", "pallet-loans", "pallet-membership", "pallet-migration-manager", @@ -7955,9 +7956,11 @@ dependencies = [ "orml-tokens", "orml-traits", "pallet-balances", + "pallet-restricted-tokens", "parity-scale-codec 3.4.0", "scale-info", "serde", + "sp-arithmetic", "sp-core", "sp-io", "sp-runtime", diff --git a/libs/primitives/src/conversion.rs b/libs/primitives/src/conversion.rs index f9ec1c2f60..aa7f249b09 100644 --- a/libs/primitives/src/conversion.rs +++ b/libs/primitives/src/conversion.rs @@ -1,7 +1,8 @@ use sp_arithmetic::{ - traits::{ensure_pow, BaseArithmetic}, + traits::{ensure_pow, AtLeast32BitUnsigned, BaseArithmetic}, ArithmeticError, FixedPointNumber, }; +use sp_runtime::traits::EnsureInto; /// Transform a fixed point number to a Balance. /// The resulting Balance will be represented with the `decimals` given. @@ -67,3 +68,42 @@ pub fn fixed_point_to_balance< new_integer_part.ensure_add(new_frac_part) } + +/// Converts a `uint` `Balance` of one precision into a `Balance` of another +/// precision i.e: +/// ```rust +/// use cfg_primitives::conversion::convert_balance_decimals; +/// # use frame_support::{assert_err, assert_ok}; +/// # use sp_runtime::DispatchError; +/// # use sp_arithmetic::ArithmeticError; +/// +/// assert_ok!(convert_balance_decimals(3u32, 6u32, 1_234_567u64), 1_234_567_000u64); +/// assert_ok!(convert_balance_decimals(6u32, 3u32, 1_234_567u64), 1_234u64); +/// assert_ok!(convert_balance_decimals(6u32, 6u32, 1_234_567u64), 1_234_567u64); +/// +/// assert_err!(convert_balance_decimals(6u32, 42u32, 1_000_000u64), ArithmeticError::Overflow); +/// ``` +pub fn convert_balance_decimals< + Precision: AtLeast32BitUnsigned + TryInto, + Balance: BaseArithmetic + Copy, +>( + from: Precision, + to: Precision, + balance: Balance, +) -> Result { + match from { + from if from == to => Ok(balance), + from if to > from => precision_diff::(to, from)?.ensure_mul(balance), + from => balance.ensure_div(precision_diff::(from, to)?), + } +} + +fn precision_diff< + Precision: AtLeast32BitUnsigned + TryInto, + Balance: BaseArithmetic + Copy, +>( + gt: Precision, + lt: Precision, +) -> Result { + ensure_pow(Balance::from(10), gt.ensure_sub(lt)?.ensure_into()?) +} diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 54ef5855c6..828619826d 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -472,35 +472,87 @@ pub trait CurrencyInspect { pub trait TokenSwaps { type CurrencyId; type Balance; + type SellRatio; type OrderId; /// Swap tokens buying a `buy_amount` of `currency_in` using the /// `currency_out` tokens. The implementer of this method should know /// the current market rate between those two currencies. - /// `sell_price_limit` defines the lowest price acceptable for + /// `sell_rate_limit` defines the highest price acceptable for /// `currency_in` currency when buying with `currency_out`. This /// protects order placer if market changes unfavourably for swap order. - /// Returns the order id created with by this buy order if it could not - /// be immediately and completely fulfilled. + /// For example, with a `sell_rate_limit` of `3/2` one asset in should never + /// cost more than 1.5 units of asset out. Returns `Result` with `OrderId` + /// upon successful order creation. + /// + /// Example usage with pallet_order_book impl: + /// OrderBook::place_order( + /// {AccountId}, + /// CurrencyId::ForeignAsset(0), + /// CurrencyId::ForeignAsset(1), + /// 100 * FOREIGN_ASSET_0_DECIMALS, + /// Quantity::checked_from_rational(3u32, 2u32).unwrap(), + /// 100 * FOREIGN_ASSET_0_DECIMALS + /// ) + /// Would return Ok({OrderId}) + /// and create the following order in storage: + /// Order { + /// order_id: {OrderId}, + /// placing_account: {AccountId}, + /// asset_in_id: CurrencyId::ForeignAsset(0), + /// asset_out_id: CurrencyId::ForeignAsset(1), + /// buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS, + /// initial_buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS, + /// sell_rate_limit: Quantity::checked_from_rational(3u32, + /// 2u32).unwrap(), min_fullfillment_amount: 100 * + /// FOREIGN_ASSET_0_DECIMALS, max_sell_amount: 150 * + /// FOREIGN_ASSET_1_DECIMALS } fn place_order( account: Account, currency_out: Self::CurrencyId, currency_in: Self::CurrencyId, buy_amount: Self::Balance, - sell_price_limit: Self::Balance, - min_fulfillment_amount: Self::Balance, + sell_rate_limit: Self::SellRatio, + min_fullfillment_amount: Self::Balance, ) -> Result; - /// Can fail for various reasons + /// Update an existing active order. + /// As with create order `sell_rate_limit` defines the highest price + /// acceptable for `currency_in` currency when buying with `currency_out`. + /// Returns a Dispatch result. + /// + /// This Can fail for various reasons /// /// E.g. min_fulfillment_amount is lower and /// the system has already fulfilled up to the previous /// one. + /// + /// Example usage with pallet_order_book impl: + /// OrderBook::update_order( + /// {AccountId}, + /// {OrderId}, + /// 15 * FOREIGN_ASSET_0_DECIMALS, + /// Quantity::checked_from_integer(2u32).unwrap(), + /// 6 * FOREIGN_ASSET_0_DECIMALS + /// ) + /// Would return Ok(()) + /// and update the following order in storage: + /// Order { + /// order_id: {OrderId}, + /// placing_account: {AccountId}, + /// asset_in_id: CurrencyId::ForeignAsset(0), + /// asset_out_id: CurrencyId::ForeignAsset(1), + /// buy_amount: 15 * FOREIGN_ASSET_0_DECIMALS, + /// initial_buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS, + /// sell_rate_limit: Quantity::checked_from_integer(2u32).unwrap(), + /// min_fullfillment_amount: 6 * FOREIGN_ASSET_0_DECIMALS, + /// max_sell_amount: 30 * FOREIGN_ASSET_1_DECIMALS + /// } fn update_order( account: Account, order_id: Self::OrderId, buy_amount: Self::Balance, - sell_price_limit: Self::Balance, - min_fulfillment_amount: Self::Balance, + sell_rate_limit: Self::SellRatio, + min_fullfillment_amount: Self::Balance, ) -> DispatchResult; /// Cancel an already active order. diff --git a/libs/types/src/ids.rs b/libs/types/src/ids.rs index dc1b843412..b0e1c82c64 100644 --- a/libs/types/src/ids.rs +++ b/libs/types/src/ids.rs @@ -35,6 +35,7 @@ pub const TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); pub const NFT_SALES_PALLET_ID: PalletId = PalletId(*b"pal/nfts"); pub const STAKE_POT_PALLET_ID: PalletId = PalletId(*b"PotStake"); pub const BLOCK_REWARDS_PALLET_ID: PalletId = PalletId(*b"cfg/blrw"); +pub const LIQUIDITY_REWARDS_PALLET_ID: PalletId = PalletId(*b"cfg/lqrw"); pub const PRICE_ORACLE_PALLET_ID: PalletId = PalletId(*b"or/price"); // Other ids diff --git a/pallets/block-rewards/src/mock.rs b/pallets/block-rewards/src/mock.rs index 70140abd3e..c6720a9e57 100644 --- a/pallets/block-rewards/src/mock.rs +++ b/pallets/block-rewards/src/mock.rs @@ -141,7 +141,12 @@ impl OnUnbalanced> for RewardRemainderMock { } orml_traits::parameter_type_with_key! { - pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { 0 }; + pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { + match currency_id { + CurrencyId::Native => ExistentialDeposit::get(), + _ => 0, + } + }; } impl orml_tokens::Config for Test { @@ -363,12 +368,9 @@ impl ExtBuilder { .assimilate_storage(&mut storage) .expect("Session pallet's storage can be assimilated"); - pallet_rewards::GenesisConfig:: { - currency_id: CurrencyId::Native, - amount: ExistentialDeposit::get(), - } - .assimilate_storage(&mut storage) - .expect("Rewards pallet's storage can be assimilated"); + pallet_rewards::GenesisConfig::::default() + .assimilate_storage(&mut storage) + .expect("Rewards pallet's storage can be assimilated"); let mut ext = sp_io::TestExternalities::new(storage); diff --git a/pallets/liquidity-rewards/src/lib.rs b/pallets/liquidity-rewards/src/lib.rs index 0fb9641e09..71d526eba1 100644 --- a/pallets/liquidity-rewards/src/lib.rs +++ b/pallets/liquidity-rewards/src/lib.rs @@ -62,7 +62,7 @@ use sp_runtime::{ FixedPointOperand, }; use sp_std::mem; -use weights::WeightInfo; +pub use weights::WeightInfo; /// Type that contains the associated data of an epoch #[derive(Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound)] diff --git a/pallets/order-book/Cargo.toml b/pallets/order-book/Cargo.toml index 79ba9a5aca..76143e8d6e 100644 --- a/pallets/order-book/Cargo.toml +++ b/pallets/order-book/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } serde = { version = "1.0.119" } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -41,22 +42,39 @@ orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-m orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = true, branch = "polkadot-v0.9.38" } # Parity crates pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = true, branch = "polkadot-v0.9.38" } +pallet-restricted-tokens = { path = "../restricted-tokens", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", default-features = true, branch = "polkadot-v0.9.38" } xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } [features] default = ['std'] + +runtime-benchmarks = [ + 'frame-benchmarking/runtime-benchmarks', + 'frame-support/runtime-benchmarks', + 'frame-system/runtime-benchmarks', + 'sp-runtime/runtime-benchmarks', + 'cfg-types/runtime-benchmarks', + 'cfg-traits/runtime-benchmarks', + 'cfg-primitives/runtime-benchmarks', + 'orml-asset-registry/runtime-benchmarks', + 'cfg-mocks/runtime-benchmarks', + 'cfg-test-utils/runtime-benchmarks', + +] + std = [ 'codec/std', 'frame-support/std', 'frame-system/std', - "frame-benchmarking/std", + 'frame-benchmarking/std', 'scale-info/std', 'serde/std', 'sp-core/std', + 'sp-arithmetic/std', 'sp-runtime/std', 'sp-std/std', - "orml-traits/std", + 'orml-traits/std', 'cfg-primitives/std', 'cfg-types/std', 'cfg-traits/std', @@ -69,15 +87,3 @@ try-runtime = [ 'cfg-types/try-runtime', 'cfg-traits/try-runtime', ] -runtime-benchmarks = [ - 'frame-benchmarking/runtime-benchmarks', - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - 'sp-runtime/runtime-benchmarks', - 'cfg-types/runtime-benchmarks', - 'cfg-traits/runtime-benchmarks', - 'cfg-primitives/runtime-benchmarks', - "orml-asset-registry/runtime-benchmarks", - "cfg-mocks/runtime-benchmarks", - "cfg-test-utils/runtime-benchmarks", -] diff --git a/pallets/order-book/src/benchmarking.rs b/pallets/order-book/src/benchmarking.rs index 468d5ddab8..60f549649f 100644 --- a/pallets/order-book/src/benchmarking.rs +++ b/pallets/order-book/src/benchmarking.rs @@ -12,57 +12,57 @@ #![cfg(feature = "runtime-benchmarks")] -use cfg_traits::fees::Fees; -use cfg_types::tokens::{CurrencyId, CustomMetadata}; +use cfg_types::{ + fixed_point::Rate, + tokens::{CurrencyId, CustomMetadata}, +}; use frame_benchmarking::*; -use frame_support::traits::{Currency, Get}; +use frame_support::traits::fungibles::Mutate as FungiblesMutate; use frame_system::RawOrigin; -use orml_traits::{ - asset_registry::{Inspect, Mutate}, - MultiCurrency, -}; +use orml_traits::asset_registry::{Inspect, Mutate}; +use sp_runtime::FixedPointNumber; // use pallet_pool_system::benchmarking::prepare_asset_registry; use super::*; -#[cfg(test)] -fn config_mocks() { - use crate::mock::Fees; - Fees::mock_fee_value(|_| 0); - Fees::mock_fee_to_author(|_, _| Ok(())); -} - -const CURRENCY_0: u128 = 1_000_000_000_000_000_000u128; -const CURRENCY_1: u128 = 1_000_000_000_000_000u128; +const CURRENCY_0: u128 = 1_000_000; +const CURRENCY_1: u128 = 1_000_000_000_000; benchmarks! { where_clause { where - T: Config, + T: Config, ::AssetRegistry: orml_traits::asset_registry::Mutate, } - create_order_v1 { + create_order { let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; - }:create_order_v1(RawOrigin::Signed(account_0.clone()), asset_0, asset_1, 100u32.into(), 10u32.into()) + }:create_order(RawOrigin::Signed(account_0.clone()), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap()) + + + user_update_order { + let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; + + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; + + }:user_update_order(RawOrigin::Signed(account_0.clone()), order_id, 150 * CURRENCY_0, Rate::checked_from_integer(1u32).unwrap()) user_cancel_order { let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; - let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100u32.into(), 10u32.into(), 100u32.into())?; + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; }:user_cancel_order(RawOrigin::Signed(account_0.clone()), order_id) fill_order_full { let (account_0, account_1, asset_0, asset_1) = set_up_users_currencies::()?; - let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100u32.into(), 10u32.into(), 100u32.into())?; + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; }:fill_order_full(RawOrigin::Signed(account_1.clone()), order_id) } -fn set_up_users_currencies>( -) -> Result< +fn set_up_users_currencies>() -> Result< ( T::AccountId, T::AccountId, @@ -74,25 +74,15 @@ fn set_up_users_currencies::AssetRegistry: orml_traits::asset_registry::Mutate, { - #[cfg(test)] - config_mocks(); let account_0: T::AccountId = account::("Account0", 1, 0); let account_1: T::AccountId = account::("Account1", 2, 0); - T::ReserveCurrency::deposit_creating( - &account_0, - T::Fees::fee_value(T::OrderFeeKey::get()) * 4u32.into(), - ); - T::ReserveCurrency::deposit_creating( - &account_1, - T::Fees::fee_value(T::OrderFeeKey::get()) * 4u32.into(), - ); - let asset_0 = CurrencyId::AUSD; - let asset_1 = CurrencyId::ForeignAsset(0); + let asset_0 = CurrencyId::ForeignAsset(1); + let asset_1 = CurrencyId::ForeignAsset(2); prepare_asset_registry::(); - T::TradeableAsset::deposit(asset_0, &account_0, 1_000 * CURRENCY_0)?; - T::TradeableAsset::deposit(asset_1, &account_0, 1_000 * CURRENCY_1)?; - T::TradeableAsset::deposit(asset_0, &account_1, 1_000 * CURRENCY_0)?; - T::TradeableAsset::deposit(asset_1, &account_1, 1_000 * CURRENCY_1)?; + T::TradeableAsset::mint_into(asset_0, &account_0, 1_000 * CURRENCY_0)?; + T::TradeableAsset::mint_into(asset_1, &account_0, 1_000 * CURRENCY_1)?; + T::TradeableAsset::mint_into(asset_0, &account_1, 1_000 * CURRENCY_0)?; + T::TradeableAsset::mint_into(asset_1, &account_1, 1_000 * CURRENCY_1)?; Ok((account_0, account_1, asset_0, asset_1)) } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime,); @@ -101,13 +91,13 @@ pub fn prepare_asset_registry() where T::AssetRegistry: Mutate, { - match T::AssetRegistry::metadata(&CurrencyId::AUSD) { + match T::AssetRegistry::metadata(&CurrencyId::ForeignAsset(1)) { Some(_) => (), None => { T::AssetRegistry::register_asset( - Some(CurrencyId::AUSD), + Some(CurrencyId::ForeignAsset(1)), orml_asset_registry::AssetMetadata { - decimals: 18, + decimals: 12, name: "MOCK TOKEN".as_bytes().to_vec(), symbol: "MOCK".as_bytes().to_vec(), existential_deposit: 0, @@ -119,13 +109,13 @@ where } } - match T::AssetRegistry::metadata(&CurrencyId::ForeignAsset(0)) { + match T::AssetRegistry::metadata(&CurrencyId::ForeignAsset(2)) { Some(_) => (), None => { T::AssetRegistry::register_asset( - Some(CurrencyId::ForeignAsset(0)), + Some(CurrencyId::ForeignAsset(2)), orml_asset_registry::AssetMetadata { - decimals: 15, + decimals: 6, name: "MOCK TOKEN 1".as_bytes().to_vec(), symbol: "MOCK1".as_bytes().to_vec(), existential_deposit: 0, diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index 836a63c681..be50ed0b7b 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -39,43 +39,45 @@ pub mod pallet { use core::fmt::Debug; - use cfg_traits::{fees::Fees, StatusNotificationHook}; + use cfg_traits::{StatusNotificationHook}; use cfg_types::{investments::Swap, tokens::CustomMetadata}; + use cfg_primitives::conversion::convert_balance_decimals; + use cfg_types::tokens::CustomMetadata; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ pallet_prelude::{DispatchResult, Member, StorageDoubleMap, StorageValue, *}, - traits::{tokens::AssetId, Currency, ReservableCurrency}, + traits::{ + fungibles::{Inspect as AssetInspect, InspectHold, Mutate, MutateHold, Transfer}, + tokens::AssetId, + }, Twox64Concat, }; use frame_system::pallet_prelude::{OriginFor, *}; use orml_traits::{ asset_registry::{self, Inspect as _}, - MultiCurrency, MultiReservableCurrency, + GetByKey, }; use scale_info::TypeInfo; + use sp_arithmetic::traits::BaseArithmetic; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, EnsureAdd, EnsureMul, EnsureSub, One, Zero}, - FixedPointOperand, + traits::{ + AtLeast32BitUnsigned, EnsureAdd, EnsureDiv, EnsureFixedPointNumber, EnsureMul, + EnsureSub, MaybeSerializeDeserialize, One, Zero, + }, + FixedPointNumber, FixedPointOperand, }; use super::*; - /// Balance type for the reserve/deposit made when creating an Allowance - pub type DepositBalanceOf = <::ReserveCurrency as Currency< - ::AccountId, - >>::Balance; - /// Order of pallet config type pub type OrderOf = Order< ::OrderIdNonce, ::AccountId, ::AssetCurrencyId, - ::ForeignCurrencyBalance, + ::Balance, + ::SellRatio, >; - - pub type FeeBalance = <::ReserveCurrency as Currency< - ::AccountId, - >>::Balance; + pub type BalanceOf = ::Balance; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -92,7 +94,7 @@ pub mod pallet { /// Asset registry for foreign currencies we can take orders for. type AssetRegistry: asset_registry::Inspect< AssetId = Self::AssetCurrencyId, - Balance = Self::ForeignCurrencyBalance, + Balance = Self::Balance, CustomMetadata = CustomMetadata, >; @@ -108,44 +110,6 @@ pub mod pallet { + TypeInfo + MaxEncodedLen; - /// Currency for Reserve/Unreserve with allowlist adding/removal, - /// given that the allowlist will be in storage - type ReserveCurrency: Currency + ReservableCurrency; - - /// Fee handler for the reserve/unreserve - /// Currently just stores the amounts, will be extended to handle - /// reserve/unreserve as well in future - /// Uses default balance type as opposed to ForeignCurrencyBalance - type Fees: Fees< - AccountId = ::AccountId, - Balance = DepositBalanceOf, - >; - - /// Fee Key used to find amount for allowance reserve/unreserve - type OrderFeeKey: Get<::FeeKey>; - - /// Token Id for token used for fee reserving - /// as represented by `AssetCurrencyId`. - /// Used for reserve-able fund checking to ensure - /// amount traded and storage fees can be reserved - /// when trading for fee currency. - /// This should typically be native chain currency. - type FeeCurrencyId: Get; - - /// Balance type for currencies we can place orders for - /// Seperate type from Balance in case different type used for other - /// currencies, i.e. when Balance is u64, but foreign currencies using - /// u128 - type ForeignCurrencyBalance: Member - + Parameter - + AtLeast32BitUnsigned - + Default - + Copy - + MaxEncodedLen - + FixedPointOperand - + TypeInfo - + TryInto<>::Balance>; - /// Type used for OrderId. OrderIdNonce ensures each /// OrderId is unique. OrderIdNonce incremented with each new order. type OrderIdNonce: Parameter @@ -158,11 +122,39 @@ pub mod pallet { + TypeInfo + MaxEncodedLen; + /// Balance type + type Balance: Member + + Parameter + + FixedPointOperand + + BaseArithmetic + + EnsureMul + + EnsureDiv + + TypeInfo + + MaxEncodedLen; + /// Type for currency orders can be made for - type TradeableAsset: MultiReservableCurrency< - Self::AccountId, - Balance = ::ForeignCurrencyBalance, - CurrencyId = Self::AssetCurrencyId, + type TradeableAsset: AssetInspect + + InspectHold + + MutateHold + + Mutate + + Transfer; + + /// Type for price ratio for cost of incoming currency relative to + /// outgoing + type SellRatio: Parameter + + Member + + FixedPointNumber + + EnsureMul + + EnsureDiv + + MaybeSerializeDeserialize + + TypeInfo + + MaxEncodedLen; + + /// Minimum order amount, this allows us to stop spammers + /// From making large number of small orders + type MinimumOrderAmount: GetByKey< + (Self::AssetCurrencyId, Self::AssetCurrencyId), + Option, >; /// Size of order id bounded vec in storage @@ -185,7 +177,7 @@ pub mod pallet { /// Order Storage item. /// Contains fields relevant to order information #[derive(Clone, Copy, Debug, Encode, Decode, Eq, PartialEq, MaxEncodedLen, TypeInfo)] - pub struct Order { + pub struct Order { pub order_id: OrderId, pub placing_account: AccountId, pub asset_in_id: AssetId, @@ -194,9 +186,10 @@ pub mod pallet { pub buy_amount: ForeignCurrencyBalance, /// Original buy amount, used for tracking amount fulfilled pub initial_buy_amount: ForeignCurrencyBalance, - /// How much currency being purchased (asset in) costs with asset sold - /// (asset out) - pub price: ForeignCurrencyBalance, + /// Maximum relative price of the asset in being purchased relative to + /// asset out ie: Rate::checked_from_rational(3u32, 2u32) would mean + /// that 1 asset in would correspond with 1.5 asset out. + pub max_sell_rate: SellRatio, /// Minimum amount of an order that can be fulfilled /// for partial fulfillment pub min_fulfillment_amount: ForeignCurrencyBalance, @@ -210,7 +203,7 @@ pub mod pallet { _, Twox64Concat, T::OrderIdNonce, - Order, + OrderOf, ResultQuery::OrderNotFound>, >; @@ -258,9 +251,9 @@ pub mod pallet { creator_account: T::AccountId, currency_in: T::AssetCurrencyId, currency_out: T::AssetCurrencyId, - buy_amount: T::ForeignCurrencyBalance, - min_fulfillment_amount: T::ForeignCurrencyBalance, - sell_price_limit: T::ForeignCurrencyBalance, + buy_amount: T::Balance, + min_fullfillment_amount: T::Balance, + sell_rate_limit: T::SellRatio, }, /// Event emitted when an order is cancelled. OrderCancelled { @@ -271,23 +264,18 @@ pub mod pallet { OrderUpdated { order_id: T::OrderIdNonce, account: T::AccountId, - buy_amount: T::ForeignCurrencyBalance, - sell_price_limit: T::ForeignCurrencyBalance, - min_fulfillment_amount: T::ForeignCurrencyBalance, - }, - /// Event emitted when an order is fulfilled. + buy_amount: T::Balance, /// Can be for either partial or total fulfillment. /// Contains amount fulfilled, and whether fulfillment was partial or /// full. - OrderFulfillment { order_id: T::OrderIdNonce, placing_account: T::AccountId, fulfilling_account: T::AccountId, partial_fulfillment: bool, - fulfillment_amount: T::ForeignCurrencyBalance, + fulfillment_amount: T::Balance, currency_in: T::AssetCurrencyId, currency_out: T::AssetCurrencyId, - sell_price_limit: T::ForeignCurrencyBalance, + sell_rate_limit: T::SellRatio, }, } @@ -302,20 +290,24 @@ pub mod pallet { /// type. ConflictingAssetIds, /// Error when an account cannot reserve or transfer the amount - /// specified for trade, or amount to be fulfilled. - InsufficientAssetFunds, - /// Error when an account does not have enough funds in chains reserve - /// currency to place order. - InsufficientReserveFunds, - /// Error when account tries to buy an invalid amount of currency -- /// currently `0`. InvalidBuyAmount, + /// Error when min order amount is invalid, currently `0` + InvalidMinimumFulfillment, /// Error when an account specifies an invalid buy price -- currently - /// `0`. - InvalidMinPrice, + /// specified for trade, or amount to be fulfilled. + InsufficientAssetFunds, + /// Error when Max price ratio is invalid + InvalidMaxPrice, + /// Error when an order amount is too small + InsufficientOrderSize, /// Error when an order is placed with a currency that is not in the /// asset registry. InvalidAssetId, + /// Error when a trade is using an invalid trading pair. + /// Currently can happen when there is not a minimum order size + /// defined for the trading pair. + InvalidTradingPair, /// Error when an operation is attempted on an order id that is not in /// storage. OrderNotFound, @@ -335,13 +327,13 @@ pub mod pallet { /// Create an order, with the minimum fulfillment amount set to the buy /// amount, as the first iteration will not have partial fulfillment #[pallet::call_index(0)] - #[pallet::weight(T::Weights::create_order_v1())] - pub fn create_order_v1( + #[pallet::weight(T::Weights::create_order())] + pub fn create_order( origin: OriginFor, asset_in: T::AssetCurrencyId, asset_out: T::AssetCurrencyId, - buy_amount: T::ForeignCurrencyBalance, - price: T::ForeignCurrencyBalance, + buy_amount: T::Balance, + price: T::SellRatio, ) -> DispatchResult { let account_id = ensure_signed(origin)?; Self::place_order( @@ -350,8 +342,28 @@ pub mod pallet { Ok(()) } - /// Cancel an existing order that had been created by calling account. + /// Update an existing order #[pallet::call_index(1)] + #[pallet::weight(T::Weights::user_update_order())] + pub fn user_update_order( + origin: OriginFor, + order_id: T::OrderIdNonce, + buy_amount: T::Balance, + price: T::SellRatio, + ) -> DispatchResult { + let account_id = ensure_signed(origin)?; + let order = >::get(order_id)?; + ensure!( + account_id == order.placing_account, + Error::::Unauthorised + ); + >::update_order( + account_id, order_id, buy_amount, price, buy_amount, + ) + } + + /// Cancel an existing order that had been created by calling account. + #[pallet::call_index(2)] #[pallet::weight(T::Weights::user_cancel_order())] pub fn user_cancel_order( origin: OriginFor, @@ -362,28 +374,24 @@ pub mod pallet { // UserOrders using Resultquery, if signed account // does not match user for order id, we will get an Err Result let order = >::get(order_id)?; - if account_id == order.placing_account { - Self::cancel_order(order_id)?; - Ok(()) - } else { - Err(DispatchError::from(Error::::Unauthorised)) - } + + ensure!( + account_id == order.placing_account, + Error::::Unauthorised + ); + Self::cancel_order(order_id)?; + Ok(()) } /// Fill an existing order, fulfilling the entire order. - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight(T::Weights::fill_order_full())] pub fn fill_order_full(origin: OriginFor, order_id: T::OrderIdNonce) -> DispatchResult { let account_id = ensure_signed(origin)?; let order = >::get(order_id)?; - // maybe move to ensure if we don't need these later - // might need decimals from currency, but should hopefully be able to use FP - // price/amounts from FP balance - - let sell_amount = order.buy_amount.ensure_mul(order.price)?; ensure!( - T::TradeableAsset::can_reserve(order.asset_in_id, &account_id, order.buy_amount), + T::TradeableAsset::can_hold(order.asset_in_id, &account_id, order.buy_amount), Error::::InsufficientAssetFunds, ); @@ -393,12 +401,14 @@ pub mod pallet { &account_id, &order.placing_account, order.buy_amount, + false, )?; T::TradeableAsset::transfer( order.asset_out_id, &order.placing_account, &account_id, - sell_amount, + order.max_sell_amount, + false, )?; Self::remove_order(order.order_id)?; @@ -419,7 +429,7 @@ pub mod pallet { currency_in: order.asset_in_id, currency_out: order.asset_out_id, fulfillment_amount: order.buy_amount, - sell_price_limit: order.price, + sell_rate_limit: order.max_sell_rate, }); Ok(()) @@ -438,36 +448,45 @@ pub mod pallet { Ok(()) } - /// Get reserve amount when fee and out currency are the same - pub fn get_combined_reserve( - sell_amount: T::ForeignCurrencyBalance, - ) -> Result, DispatchError> { - let fee_amount = T::Fees::fee_value(T::OrderFeeKey::get()); + /// Unreserve funds for an order that is finished either + /// through fulfillment or cancellation. + pub fn unreserve_order(order: &OrderOf) -> Result, DispatchError> { + T::TradeableAsset::release( + order.asset_out_id, + &order.placing_account, + order.max_sell_amount, + false, + ) + } - let sell_reserve_balance: FeeBalance = sell_amount - .try_into() - .map_err(|_| Error::::BalanceConversionErr)?; - Ok(sell_reserve_balance.ensure_add(fee_amount)?) + /// Check min order amount + pub fn is_valid_min_order( + currency_in: T::AssetCurrencyId, + currency_out: T::AssetCurrencyId, + buy_amount: T::Balance, + ) -> DispatchResult { + match T::MinimumOrderAmount::get(&(currency_in, currency_out)) { + Some(amount) if amount <= buy_amount => Ok(()), + None => Err(Error::::InvalidTradingPair)?, + _ => Err(Error::::InsufficientOrderSize)?, + } } - /// Unreserve funds for an order that is finished either - /// through fulfillment or cancellation. - pub fn unreserve_order(order: &OrderOf) -> Result<(), DispatchError> { - if T::FeeCurrencyId::get() == order.asset_out_id { - let total_reserve_amount = Self::get_combined_reserve(order.max_sell_amount)?; - T::ReserveCurrency::unreserve(&order.placing_account, total_reserve_amount); - } else { - T::TradeableAsset::unreserve( - order.asset_out_id, - &order.placing_account, - order.max_sell_amount, - ); - T::ReserveCurrency::unreserve( - &order.placing_account, - T::Fees::fee_value(T::OrderFeeKey::get()), - ); - }; - Ok(()) + pub fn convert_with_ratio( + currency_from: T::AssetCurrencyId, + currency_to: T::AssetCurrencyId, + ratio: T::SellRatio, + amount: T::Balance, + ) -> Result { + let from_decimals = T::AssetRegistry::metadata(¤cy_from) + .ok_or(Error::::InvalidAssetId)? + .decimals; + + let to_decimals = T::AssetRegistry::metadata(¤cy_to) + .ok_or(Error::::InvalidAssetId)? + .decimals; + convert_balance_decimals(from_decimals, to_decimals, ratio.ensure_mul_int(amount)?) + .map_err(DispatchError::from) } } @@ -475,9 +494,10 @@ pub mod pallet { where ::Hash: PartialEq<::Hash>, { - type Balance = T::ForeignCurrencyBalance; + type Balance = T::Balance; type CurrencyId = T::AssetCurrencyId; type OrderId = T::OrderIdNonce; + type SellRatio = T::SellRatio; /// Creates an order. /// Verify funds available in, and reserve for both chains fee currency @@ -487,43 +507,36 @@ pub mod pallet { account: T::AccountId, currency_in: T::AssetCurrencyId, currency_out: T::AssetCurrencyId, - buy_amount: T::ForeignCurrencyBalance, - sell_price_limit: T::ForeignCurrencyBalance, - min_fulfillment_amount: T::ForeignCurrencyBalance, + buy_amount: T::Balance, + sell_rate_limit: T::SellRatio, + min_fullfillment_amount: T::Balance, ) -> Result { ensure!(currency_in != currency_out, Error::::ConflictingAssetIds); ensure!( - buy_amount != T::ForeignCurrencyBalance::zero(), - Error::::InvalidBuyAmount - ); - ensure!( - sell_price_limit != T::ForeignCurrencyBalance::zero(), - Error::::InvalidMinPrice - ); - ensure!( - T::AssetRegistry::metadata(¤cy_in).is_some(), - Error::::InvalidAssetId - ); + min_fullfillment_amount != ::zero(), + Error::::InvalidMinimumFulfillment ensure!( - T::AssetRegistry::metadata(¤cy_out).is_some(), - Error::::InvalidAssetId + sell_rate_limit != T::SellRatio::zero(), + Error::::InvalidMaxPrice ); + >::try_mutate(|n| { *n = n.ensure_add(T::OrderIdNonce::one())?; Ok::<_, DispatchError>(()) })?; - let max_sell_amount = buy_amount.ensure_mul(sell_price_limit)?; - let fee_amount = T::Fees::fee_value(T::OrderFeeKey::get()); - if T::FeeCurrencyId::get() == currency_out { - let total_reserve_amount = Self::get_combined_reserve(max_sell_amount)?; - T::ReserveCurrency::reserve(&account, total_reserve_amount)?; - } else { - T::ReserveCurrency::reserve(&account, fee_amount)?; + ensure!( + buy_amount >= min_fullfillment_amount, + Error::::InvalidBuyAmount + ); + + Self::is_valid_min_order(currency_in, currency_out, buy_amount)?; - T::TradeableAsset::reserve(currency_out, &account, max_sell_amount)?; - } + let max_sell_amount = + Self::convert_with_ratio(currency_in, currency_out, sell_rate_limit, buy_amount)?; + + T::TradeableAsset::hold(currency_out, &account, max_sell_amount)?; let order_id = >::get(); let new_order = Order { @@ -532,7 +545,7 @@ pub mod pallet { asset_in_id: currency_in, asset_out_id: currency_out, buy_amount, - price: sell_price_limit, + max_sell_rate: sell_rate_limit, initial_buy_amount: buy_amount, min_fulfillment_amount, max_sell_amount, @@ -548,7 +561,7 @@ pub mod pallet { >::insert(&account, order_id, new_order); Self::deposit_event(Event::OrderCreated { creator_account: account, - sell_price_limit, + sell_rate_limit, order_id, buy_amount, currency_in, @@ -580,75 +593,83 @@ pub mod pallet { fn update_order( account: T::AccountId, order_id: Self::OrderId, - buy_amount: T::ForeignCurrencyBalance, - sell_price_limit: T::ForeignCurrencyBalance, - min_fulfillment_amount: T::ForeignCurrencyBalance, + buy_amount: T::Balance, + sell_rate_limit: T::SellRatio, + min_fullfillment_amount: T::Balance, ) -> DispatchResult { ensure!( - buy_amount != T::ForeignCurrencyBalance::zero(), + buy_amount != T::Balance::zero(), Error::::InvalidBuyAmount ); + ensure!( - sell_price_limit != T::ForeignCurrencyBalance::zero(), - Error::::InvalidMinPrice + sell_rate_limit != T::SellRatio::zero(), + Error::::InvalidMaxPrice ); - >::try_mutate_exists(order_id, |maybe_order| -> DispatchResult { - let mut order = maybe_order.as_mut().ok_or(Error::::OrderNotFound)?; - - let max_sell_amount = buy_amount.ensure_mul(sell_price_limit)?; - // ensure proper amount can be, and is reserved of outgoing currency for updated - // order. - // Also minimise reserve/unreserve operations. - if buy_amount != order.buy_amount || sell_price_limit != order.price { - if max_sell_amount > order.max_sell_amount { - let sell_reserve_diff = - max_sell_amount.ensure_sub(order.max_sell_amount)?; - if T::FeeCurrencyId::get() == order.asset_out_id { - let sell_reserve_diff_balance: FeeBalance = sell_reserve_diff - .try_into() - .map_err(|_| Error::::BalanceConversionErr)?; - T::ReserveCurrency::reserve(&account, sell_reserve_diff_balance)? - } else { - T::TradeableAsset::reserve( + ensure!( + min_fullfillment_amount != ::zero(), + Error::::InvalidMinimumFulfillment + ); + + ensure!( + buy_amount >= min_fullfillment_amount, + Error::::InvalidBuyAmount + ); + + let max_sell_amount = >::try_mutate_exists( + order_id, + |maybe_order| -> Result { + let mut order = maybe_order.as_mut().ok_or(Error::::OrderNotFound)?; + Self::is_valid_min_order(order.asset_in_id, order.asset_out_id, buy_amount)?; + + let max_sell_amount = Self::convert_with_ratio( + order.asset_in_id, + order.asset_out_id, + sell_rate_limit, + buy_amount, + )?; + + // ensure proper amount can be, and is reserved of outgoing currency for updated + // order. + // Also minimise reserve/unreserve operations. + if buy_amount != order.buy_amount || sell_rate_limit != order.max_sell_rate { + if max_sell_amount > order.max_sell_amount { + let sell_reserve_diff = + max_sell_amount.ensure_sub(order.max_sell_amount)?; + T::TradeableAsset::hold( order.asset_out_id, &account, sell_reserve_diff, )?; - } - } else { - let sell_reserve_diff = - order.max_sell_amount.ensure_sub(max_sell_amount)?; - if T::FeeCurrencyId::get() == order.asset_out_id { - let sell_reserve_diff_balance: FeeBalance = sell_reserve_diff - .try_into() - .map_err(|_| Error::::BalanceConversionErr)?; - T::ReserveCurrency::unreserve(&account, sell_reserve_diff_balance); } else { - T::TradeableAsset::unreserve( + let sell_reserve_diff = + order.max_sell_amount.ensure_sub(max_sell_amount)?; + T::TradeableAsset::release( order.asset_out_id, &account, sell_reserve_diff, - ); + false, + )?; } - } - }; - order.buy_amount = buy_amount; - order.price = sell_price_limit; - order.min_fulfillment_amount = min_fulfillment_amount; - order.max_sell_amount = max_sell_amount; - - Ok(()) - })?; + }; + order.buy_amount = buy_amount; + order.max_sell_rate = sell_rate_limit; + order.min_fullfillment_amount = min_fullfillment_amount; + order.max_sell_amount = max_sell_amount; + + Ok(max_sell_amount) + }, + )?; + >::try_mutate_exists( &account, order_id, |maybe_order| -> DispatchResult { let mut order = maybe_order.as_mut().ok_or(Error::::OrderNotFound)?; - let max_sell_amount = buy_amount.ensure_mul(sell_price_limit)?; order.buy_amount = buy_amount; - order.price = sell_price_limit; - order.min_fulfillment_amount = min_fulfillment_amount; + order.max_sell_rate = sell_rate_limit; + order.min_fullfillment_amount = min_fullfillment_amount; order.max_sell_amount = max_sell_amount; Ok(()) }, @@ -657,8 +678,8 @@ pub mod pallet { account, order_id, buy_amount, - sell_price_limit, - min_fulfillment_amount, + sell_rate_limit, + min_fullfillment_amount, }); Ok(()) diff --git a/pallets/order-book/src/mock.rs b/pallets/order-book/src/mock.rs index 0e7b69e396..eaa9e5e2e8 100644 --- a/pallets/order-book/src/mock.rs +++ b/pallets/order-book/src/mock.rs @@ -16,10 +16,12 @@ use cfg_types::{ investments::Swap, tokens::{CurrencyId, CustomMetadata}, }; +use cfg_primitives::CFG; +use cfg_types::tokens::{CurrencyId, CustomMetadata}; use frame_support::{ pallet_prelude::DispatchResult, parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU128, ConstU32, GenesisBuild}, }; use orml_traits::{asset_registry::AssetMetadata, parameter_type_with_key}; use sp_core::H256; @@ -33,16 +35,24 @@ use crate as order_book; pub(crate) const STARTING_BLOCK: u64 = 50; pub(crate) const ACCOUNT_0: u64 = 0x1; pub(crate) const ACCOUNT_1: u64 = 0x2; -pub(crate) const ORDER_FEEKEY: u8 = 0u8; -pub(crate) const ORDER_FEEKEY_AMOUNT: u64 = 10u64; -pub(crate) const CURRENCY_A: ForeignCurrencyBalance = 1_000_000_000_000_000_000; -// To ensure price/amount calculations with different -// currency precision works -pub(crate) const CURRENCY_B: ForeignCurrencyBalance = 1_000_000_000_000_000; +// Minimum order amounts for orderbook orders v1 implementation. +// This will be replaced by runtime specifiable minimum, +// which will likely be set by governance. +pub(crate) const DEV_USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); +pub(crate) const DEV_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); +pub(crate) const FOREIGN_CURRENCY_NO_MIN_ID: CurrencyId = CurrencyId::ForeignAsset(3); +pub(crate) const CURRENCY_USDT_DECIMALS: u128 = 1_000_000; +pub(crate) const CURRENCY_AUSD_DECIMALS: u128 = 1_000_000_000_000; +pub(crate) const CURRENCY_NO_MIN_DECIMALS: u128 = 1_000_000_000_000; +pub(crate) const CURRENCY_NATIVE_DECIMALS: Balance = CFG; -type Balance = u64; -type ForeignCurrencyBalance = u128; +const DEFAULT_DEV_MIN_ORDER: u128 = 5; +const MIN_DEV_USDT_ORDER: Balance = DEFAULT_DEV_MIN_ORDER * CURRENCY_USDT_DECIMALS; +const MIN_DEV_AUSD_ORDER: Balance = DEFAULT_DEV_MIN_ORDER * CURRENCY_AUSD_DECIMALS; +const MIN_DEV_NATIVE_ORDER: Balance = DEFAULT_DEV_MIN_ORDER * CURRENCY_NATIVE_DECIMALS; + +type Balance = u128; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; pub type MockAccountId = u64; @@ -58,6 +68,7 @@ frame_support::construct_runtime!( System: frame_system, OrmlTokens: orml_tokens, OrderBook: order_book, + Tokens: pallet_restricted_tokens, } ); @@ -104,9 +115,9 @@ parameter_types! { impl pallet_balances::Config for Runtime { type AccountStore = System; - type Balance = u64; + type Balance = Balance; type DustRemoval = (); - type ExistentialDeposit = ConstU64<1>; + type ExistentialDeposit = ConstU128<1>; type MaxLocks = (); type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; @@ -117,19 +128,19 @@ impl pallet_balances::Config for Runtime { cfg_test_utils::mocks::orml_asset_registry::impl_mock_registry! { RegistryMock, CurrencyId, - ForeignCurrencyBalance, + Balance, CustomMetadata } parameter_type_with_key! { - pub ExistentialDeposits: |_currency_id: CurrencyId| -> ForeignCurrencyBalance { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { Default::default() }; } impl orml_tokens::Config for Runtime { type Amount = i64; - type Balance = u128; + type Balance = Balance; type CurrencyHooks = (); type CurrencyId = CurrencyId; type DustRemovalWhitelist = frame_support::traits::Nothing; @@ -142,11 +153,34 @@ impl orml_tokens::Config for Runtime { } parameter_types! { - pub const OrderFeeKey: u8 = ORDER_FEEKEY; + + pub const NativeToken: CurrencyId = CurrencyId::Native; +} + +impl pallet_restricted_tokens::Config for Runtime { + type Balance = Balance; + type CurrencyId = CurrencyId; + type Fungibles = OrmlTokens; + type NativeFungible = Balances; + type NativeToken = NativeToken; + type PreCurrency = cfg_traits::Always; + type PreExtrTransfer = cfg_traits::Always; + type PreFungibleInspect = pallet_restricted_tokens::FungibleInspectPassthrough; + type PreFungibleInspectHold = cfg_traits::Always; + type PreFungibleMutate = cfg_traits::Always; + type PreFungibleMutateHold = cfg_traits::Always; + type PreFungibleTransfer = cfg_traits::Always; + type PreFungiblesInspect = pallet_restricted_tokens::FungiblesInspectPassthrough; + type PreFungiblesInspectHold = cfg_traits::Always; + type PreFungiblesMutate = cfg_traits::Always; + type PreFungiblesMutateHold = cfg_traits::Always; + type PreFungiblesTransfer = cfg_traits::Always; + type PreReservableCurrency = cfg_traits::Always; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } parameter_types! { - pub const FeeCurrencyId: CurrencyId = CurrencyId::Native; pub const OrderPairVecSize: u32 = 1_000_000u32; } @@ -159,22 +193,31 @@ impl StatusNotificationHook for DummyHook { fn notify_status_change(_id: u64, _status: Self::Status) -> DispatchResult { Ok(()) } +parameter_type_with_key! { + pub MinimumOrderAmount: |pair: (CurrencyId, CurrencyId)| -> Option { + match pair { + (CurrencyId::Native, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_AUSD_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_AUSD_ORDER), + (CurrencyId::Native, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_USDT_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_USDT_ORDER), + (DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_AUSD_ORDER), + (DEV_USDT_CURRENCY_ID, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_USDT_ORDER), + _ => None + } + }; } impl order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = RegistryMock; - type FeeCurrencyId = FeeCurrencyId; - // type Balance = Balance; - type Fees = Fees; - type ForeignCurrencyBalance = ForeignCurrencyBalance; + type Balance = Balance; type FulfilledOrderHook = DummyHook; - type OrderFeeKey = OrderFeeKey; + type MinimumOrderAmount = MinimumOrderAmount; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; - type ReserveCurrency = Balances; type RuntimeEvent = RuntimeEvent; - type TradeableAsset = OrmlTokens; + type SellRatio = cfg_types::fixed_point::Rate; + type TradeableAsset = Tokens; type Weights = (); } @@ -183,22 +226,20 @@ pub fn new_test_ext() -> sp_io::TestExternalities { .build_storage::() .unwrap(); - // Add native balances for reserve/unreserve storage fees - pallet_balances::GenesisConfig:: { - balances: vec![(ACCOUNT_0, 300), (ACCOUNT_1, 300)], - } - .assimilate_storage(&mut t) - .unwrap(); - // Add foreign currency balances of differing precisions orml_tokens::GenesisConfig:: { balances: (0..3) .into_iter() .flat_map(|idx| { [ - (idx, CurrencyId::AUSD, 1000 * CURRENCY_A), - (idx, CurrencyId::ForeignAsset(0), 1000 * CURRENCY_B), - (idx, CurrencyId::Native, 100 * CURRENCY_A), + (idx, DEV_AUSD_CURRENCY_ID, 1000 * CURRENCY_AUSD_DECIMALS), + (idx, DEV_USDT_CURRENCY_ID, 1000 * CURRENCY_USDT_DECIMALS), + ( + idx, + FOREIGN_CURRENCY_NO_MIN_ID, + 1000 * CURRENCY_NO_MIN_DECIMALS, + ), + (idx, CurrencyId::Native, 100 * CURRENCY_NATIVE_DECIMALS), ] }) .collect(), @@ -209,9 +250,9 @@ pub fn new_test_ext() -> sp_io::TestExternalities { orml_asset_registry_mock::GenesisConfig { metadata: vec![ ( - CurrencyId::AUSD, + DEV_AUSD_CURRENCY_ID, AssetMetadata { - decimals: 18, + decimals: 12, name: "MOCK TOKEN_A".as_bytes().to_vec(), symbol: "MOCK_A".as_bytes().to_vec(), existential_deposit: 0, @@ -220,9 +261,20 @@ pub fn new_test_ext() -> sp_io::TestExternalities { }, ), ( - CurrencyId::ForeignAsset(0), + DEV_USDT_CURRENCY_ID, + AssetMetadata { + decimals: 6, + name: "MOCK TOKEN_B".as_bytes().to_vec(), + symbol: "MOCK_B".as_bytes().to_vec(), + existential_deposit: 0, + location: None, + additional: CustomMetadata::default(), + }, + ), + ( + FOREIGN_CURRENCY_NO_MIN_ID, AssetMetadata { - decimals: 15, + decimals: 6, name: "MOCK TOKEN_B".as_bytes().to_vec(), symbol: "MOCK_B".as_bytes().to_vec(), existential_deposit: 0, @@ -250,10 +302,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { e.execute_with(|| { System::set_block_number(STARTING_BLOCK); - Fees::mock_fee_value(|key| match key { - ORDER_FEEKEY => ORDER_FEEKEY_AMOUNT.into(), - _ => panic!("No valid fee key"), - }); }); e } diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index 7723c42867..3c59ed2011 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -1,19 +1,32 @@ -use cfg_types::tokens::CurrencyId; +// Copyright 2023 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::{fixed_point::Rate, tokens::CurrencyId}; use frame_support::{assert_err, assert_ok}; +use sp_runtime::{traits::Zero, FixedPointNumber}; use super::*; use crate::mock::*; // Extrinsics tests #[test] -fn create_order_v1_works() { +fn create_order_works() { new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( + assert_ok!(OrderBook::create_order( RuntimeOrigin::signed(ACCOUNT_0), - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3, 2).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_eq!( @@ -21,13 +34,13 @@ fn create_order_v1_works() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 100, - initial_buy_amount: 100, - price: 10, - min_fulfillment_amount: 100, - max_sell_amount: 1000 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( @@ -35,31 +48,89 @@ fn create_order_v1_works() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 100, - initial_buy_amount: 100, - price: 10, - min_fulfillment_amount: 100, - max_sell_amount: 1000 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - AssetPairOrders::::get(CurrencyId::AUSD, CurrencyId::ForeignAsset(0)), + AssetPairOrders::::get(DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID), vec![order_id,] ) }) } +#[test] +fn user_update_order_works() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::create_order( + RuntimeOrigin::signed(ACCOUNT_0), + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3, 2).unwrap() + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_ok!(OrderBook::user_update_order( + RuntimeOrigin::signed(ACCOUNT_0), + order_id, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(2u32).unwrap(), + )); + + assert_eq!( + Orders::::get(order_id), + Ok(Order { + order_id: order_id, + placing_account: ACCOUNT_0, + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + min_fullfillment_amount: 15 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 30 * CURRENCY_USDT_DECIMALS + }) + ); + }) +} + +#[test] +fn user_update_order_only_works_for_valid_account() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::create_order( + RuntimeOrigin::signed(ACCOUNT_0), + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3, 2).unwrap() + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_err!( + OrderBook::user_update_order( + RuntimeOrigin::signed(ACCOUNT_1), + order_id, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(2u32).unwrap(), + ), + Error::::Unauthorised + ); + }) +} + #[test] fn user_cancel_order_works() { new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( + assert_ok!(OrderBook::create_order( RuntimeOrigin::signed(ACCOUNT_0), - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_ok!(OrderBook::user_cancel_order( @@ -77,7 +148,7 @@ fn user_cancel_order_works() { ); assert_eq!( - AssetPairOrders::::get(CurrencyId::AUSD, CurrencyId::ForeignAsset(0)), + AssetPairOrders::::get(DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID), vec![] ) }) @@ -86,12 +157,12 @@ fn user_cancel_order_works() { #[test] fn user_cancel_order_only_works_for_valid_account() { new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( + assert_ok!(OrderBook::create_order( RuntimeOrigin::signed(ACCOUNT_0), - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -105,13 +176,13 @@ fn user_cancel_order_only_works_for_valid_account() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 100, - initial_buy_amount: 100, - price: 10, - min_fulfillment_amount: 100, - max_sell_amount: 1000 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); }) @@ -120,12 +191,12 @@ fn user_cancel_order_only_works_for_valid_account() { #[test] fn fill_order_full_works() { new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( + assert_ok!(OrderBook::create_order( RuntimeOrigin::signed(ACCOUNT_0), - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 10000, - 2 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; // verify fulfill runs @@ -145,97 +216,35 @@ fn fill_order_full_works() { ); assert_eq!( - AssetPairOrders::::get(CurrencyId::AUSD, CurrencyId::ForeignAsset(0)), + AssetPairOrders::::get(DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID), vec![] ); assert_eq!( - System::events()[3].event, + System::events()[2].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Unreserved { - currency_id: CurrencyId::ForeignAsset(0), + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - amount: 20000 + amount: 150 * CURRENCY_USDT_DECIMALS }) ); - assert_eq!( - System::events()[4].event, - RuntimeEvent::Balances(pallet_balances::Event::Unreserved { - who: ACCOUNT_0, - amount: 10 - }) - ); - assert_eq!( - System::events()[5].event, - RuntimeEvent::OrmlTokens(orml_tokens::Event::Transfer { - currency_id: CurrencyId::AUSD, - to: ACCOUNT_0, - from: ACCOUNT_1, - amount: 10000 - }) - ); - assert_eq!( - System::events()[6].event, - RuntimeEvent::OrmlTokens(orml_tokens::Event::Transfer { - currency_id: CurrencyId::ForeignAsset(0), - to: ACCOUNT_1, - from: ACCOUNT_0, - amount: 20000 - }) - ); - }); -} - -#[test] -fn fill_order_full_correctly_consolidates_reserves_with_same_out_and_fee_currency() { - new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( - RuntimeOrigin::signed(ACCOUNT_0), - CurrencyId::ForeignAsset(0), - CurrencyId::Native, - 10, - 2 - )); - let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; - // verify fulfill runs - assert_ok!(OrderBook::fill_order_full( - RuntimeOrigin::signed(ACCOUNT_1), - order_id - )); - // verify filled order removed - assert_err!( - Orders::::get(order_id), - Error::::OrderNotFound - ); - - assert_err!( - UserOrders::::get(ACCOUNT_0, order_id), - Error::::OrderNotFound - ); - - assert_eq!( - System::events()[2].event, - RuntimeEvent::Balances(pallet_balances::Event::Unreserved { - who: ACCOUNT_0, - amount: 30 - }) - ); assert_eq!( System::events()[3].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Transfer { - currency_id: CurrencyId::ForeignAsset(0), + currency_id: DEV_AUSD_CURRENCY_ID, to: ACCOUNT_0, from: ACCOUNT_1, - amount: 10 + amount: 100 * CURRENCY_AUSD_DECIMALS }) ); assert_eq!( System::events()[4].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Transfer { - currency_id: CurrencyId::Native, + currency_id: DEV_USDT_CURRENCY_ID, to: ACCOUNT_1, from: ACCOUNT_0, - amount: 20 + amount: 150 * CURRENCY_USDT_DECIMALS }) ); }); @@ -244,18 +253,18 @@ fn fill_order_full_correctly_consolidates_reserves_with_same_out_and_fee_currenc #[test] fn fill_order_full_checks_asset_in_for_fulfiller() { new_test_ext().execute_with(|| { - assert_ok!(OrderBook::create_order_v1( + assert_ok!(OrderBook::create_order( RuntimeOrigin::signed(ACCOUNT_0), CurrencyId::Native, - CurrencyId::AUSD, - 400 * CURRENCY_A, - 2 + DEV_AUSD_CURRENCY_ID, + 400 * CURRENCY_NATIVE_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; // verify fulfill runs assert_err!( OrderBook::fill_order_full(RuntimeOrigin::signed(ACCOUNT_1), order_id), - Error::::InsufficientAssetFunds + pallet_balances::Error::::InsufficientBalance ); }); } @@ -266,11 +275,11 @@ fn place_order_works() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 100 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_eq!( @@ -278,13 +287,13 @@ fn place_order_works() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 100, - initial_buy_amount: 100, - price: 10, - min_fulfillment_amount: 100, - max_sell_amount: 1000 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); @@ -293,61 +302,54 @@ fn place_order_works() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 100, - initial_buy_amount: 100, - price: 10, - min_fulfillment_amount: 100, - max_sell_amount: 1000 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - AssetPairOrders::::get(CurrencyId::AUSD, CurrencyId::ForeignAsset(0)), + AssetPairOrders::::get(DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID), vec![order_id,] ); assert_eq!( System::events()[0].event, - RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: ACCOUNT_0, - amount: 10 - }) - ); - assert_eq!( - System::events()[1].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Reserved { - currency_id: CurrencyId::ForeignAsset(0), + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - amount: 1000 + amount: 150 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - System::events()[2].event, + System::events()[1].event, RuntimeEvent::OrderBook(Event::OrderCreated { order_id: order_id, creator_account: ACCOUNT_0, - currency_in: CurrencyId::AUSD, - currency_out: CurrencyId::ForeignAsset(0), - buy_amount: 100, - min_fulfillment_amount: 100, - sell_price_limit: 10 + currency_in: DEV_AUSD_CURRENCY_ID, + currency_out: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + min_fullfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, + sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap(), }) ); }) } #[test] -fn place_order_consolidates_reserve_when_fee_matches_out() { +fn place_order_bases_max_sell_off_buy() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::ForeignAsset(0), - CurrencyId::Native, - 10, - 2, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 10 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_eq!( @@ -355,21 +357,13 @@ fn place_order_consolidates_reserve_when_fee_matches_out() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::ForeignAsset(0), - asset_out_id: CurrencyId::Native, - buy_amount: 10, - initial_buy_amount: 10, - price: 2, - min_fulfillment_amount: 10, - max_sell_amount: 20 - }) - ); - - assert_eq!( - System::events()[0].event, - RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: ACCOUNT_0, - amount: 30 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 10 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) ); @@ -378,11 +372,11 @@ fn place_order_consolidates_reserve_when_fee_matches_out() { RuntimeEvent::OrderBook(Event::OrderCreated { order_id: order_id, creator_account: ACCOUNT_0, - currency_in: CurrencyId::ForeignAsset(0), - currency_out: CurrencyId::Native, - buy_amount: 10, - min_fulfillment_amount: 10, - sell_price_limit: 2 + currency_in: DEV_AUSD_CURRENCY_ID, + currency_out: DEV_USDT_CURRENCY_ID, + buy_amount: 100 * CURRENCY_AUSD_DECIMALS, + min_fullfillment_amount: 10 * CURRENCY_AUSD_DECIMALS, + sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap(), }) ); }) @@ -393,19 +387,19 @@ fn ensure_nonce_updates_order_correctly() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 100 * CURRENCY_AUSD_DECIMALS )); assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 100 * CURRENCY_AUSD_DECIMALS )); let [(order_id_0, _), (order_id_1, _)] = get_account_orders(ACCOUNT_0) .unwrap() @@ -416,16 +410,67 @@ fn ensure_nonce_updates_order_correctly() { } #[test] -fn place_order_requires_non_zero_buy() { +fn place_order_requires_min_buy() { new_test_ext().execute_with(|| { assert_err!( OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 0, - 10, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 1 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 1 * CURRENCY_AUSD_DECIMALS, + ), + Error::::InsufficientOrderSize + ); + }) +} + +#[test] +fn place_order_requires_pair_with_defined_min() { + new_test_ext().execute_with(|| { + assert_err!( + OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + FOREIGN_CURRENCY_NO_MIN_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 1 * CURRENCY_AUSD_DECIMALS, + ), + Error::::InvalidTradingPair + ); + }) +} + +#[test] +fn place_order_requires_non_zero_min_fulfillment() { + new_test_ext().execute_with(|| { + assert_err!( + OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 0 + ), + Error::::InvalidMinimumFulfillment + ); + }) +} + +#[test] +fn place_order_min_fulfillment_cannot_be_less_than_buy() { + new_test_ext().execute_with(|| { + assert_err!( + OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 11 * CURRENCY_AUSD_DECIMALS ), Error::::InvalidBuyAmount ); @@ -438,13 +483,13 @@ fn place_order_requires_non_zero_price() { assert_err!( OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 0, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::zero(), + 100 * CURRENCY_AUSD_DECIMALS ), - Error::::InvalidMinPrice + Error::::InvalidMaxPrice ); }) } @@ -454,11 +499,11 @@ fn cancel_order_works() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10, - 100 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 100 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 100 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_ok!(OrderBook::cancel_order(order_id)); @@ -473,27 +518,19 @@ fn cancel_order_works() { ); assert_eq!( - AssetPairOrders::::get(CurrencyId::AUSD, CurrencyId::ForeignAsset(0)), + AssetPairOrders::::get(DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID), vec![] ); assert_eq!( - System::events()[3].event, + System::events()[2].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Unreserved { - currency_id: CurrencyId::ForeignAsset(0), - who: ACCOUNT_0, - amount: 1000 - }) - ); - - assert_eq!( - System::events()[4].event, - RuntimeEvent::Balances(pallet_balances::Event::Unreserved { + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - amount: 10 + amount: 150 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - System::events()[5].event, + System::events()[3].event, RuntimeEvent::OrderBook(Event::OrderCancelled { order_id, account: ACCOUNT_0, @@ -503,65 +540,36 @@ fn cancel_order_works() { } #[test] -fn cancel_unreserves_correctly_when_reserve_out_same() { +fn update_order_works_with_order_increase() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::ForeignAsset(0), - CurrencyId::Native, - 10, - 2, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; - assert_ok!(OrderBook::cancel_order(order_id)); - assert_err!( - Orders::::get(order_id), - Error::::OrderNotFound - ); - - assert_eq!( - System::events()[2].event, - RuntimeEvent::Balances(pallet_balances::Event::Unreserved { - who: ACCOUNT_0, - amount: 30 - }) - ); - assert_eq!( - System::events()[3].event, - RuntimeEvent::OrderBook(Event::OrderCancelled { - order_id, - account: ACCOUNT_0, - }) - ); - }); -} - -#[test] -fn update_order_works() { - new_test_ext().execute_with(|| { - assert_ok!(OrderBook::place_order( + assert_ok!(OrderBook::update_order( ACCOUNT_0, - CurrencyId::AUSD, - CurrencyId::ForeignAsset(0), - 100, - 10, - 100 + order_id, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS )); - let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; - assert_ok!(OrderBook::update_order(ACCOUNT_0, order_id, 110, 20, 110)); assert_eq!( Orders::::get(order_id), Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 110, - initial_buy_amount: 100, - price: 20, - min_fulfillment_amount: 110, - max_sell_amount: 2200 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 30 * CURRENCY_USDT_DECIMALS }) ); @@ -570,144 +578,184 @@ fn update_order_works() { Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_in_id: CurrencyId::AUSD, - asset_out_id: CurrencyId::ForeignAsset(0), - buy_amount: 110, - initial_buy_amount: 100, - price: 20, - min_fulfillment_amount: 110, - max_sell_amount: 2200 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 30 * CURRENCY_USDT_DECIMALS }) ); + // create order reserve assert_eq!( - System::events()[1].event, + System::events()[0].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Reserved { - currency_id: CurrencyId::ForeignAsset(0), + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, // order create reserve - amount: 1000 + amount: 15 * CURRENCY_USDT_DECIMALS }) ); + assert_eq!( - System::events()[3].event, + System::events()[2].event, RuntimeEvent::OrmlTokens(orml_tokens::Event::Reserved { - currency_id: CurrencyId::ForeignAsset(0), + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - // update reserve additional 1200 needed to cover new price and amount - amount: 1200 + // update reserve additional 15 needed to cover new price and amount + amount: 15 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - System::events()[4].event, + System::events()[3].event, RuntimeEvent::OrderBook(Event::OrderUpdated { order_id, account: ACCOUNT_0, - buy_amount: 110, - min_fulfillment_amount: 110, - sell_price_limit: 20 + buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + sell_rate_limit: Rate::checked_from_integer(2u32).unwrap() }) ); }) } #[test] -fn update_order_consolidates_reserve_increase_when_asset_out_fee_currency() { +fn update_order_updates_min_fulfillment() { + // verify both that min fulfillment updated correctly, + // and no reserve update new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::ForeignAsset(0), - CurrencyId::Native, - 10, - 2, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; - assert_ok!(OrderBook::update_order(ACCOUNT_0, order_id, 10, 3, 10)); + assert_ok!(OrderBook::update_order( + ACCOUNT_0, + order_id, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 6 * CURRENCY_AUSD_DECIMALS + )); assert_eq!( Orders::::get(order_id), Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_out_id: CurrencyId::Native, - asset_in_id: CurrencyId::ForeignAsset(0), - buy_amount: 10, - initial_buy_amount: 10, - price: 3, - min_fulfillment_amount: 10, - max_sell_amount: 30 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 15 * CURRENCY_USDT_DECIMALS }) ); assert_eq!( - System::events()[0].event, - RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: ACCOUNT_0, - amount: 30 + UserOrders::::get(ACCOUNT_0, order_id), + Ok(Order { + order_id: order_id, + placing_account: ACCOUNT_0, + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + + max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + min_fullfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 15 * CURRENCY_USDT_DECIMALS }) ); + + // events 0 and 1 are create order reserve, and create orcer + // should be no other reserve/unreserve events before update assert_eq!( System::events()[2].event, - RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: ACCOUNT_0, - // amount increased of outgoing currency increased by 10 - amount: 10 - }) - ); - assert_eq!( - System::events()[3].event, RuntimeEvent::OrderBook(Event::OrderUpdated { order_id, account: ACCOUNT_0, - buy_amount: 10, - min_fulfillment_amount: 10, - sell_price_limit: 3 + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + min_fullfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, + sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap() }) ); }) } #[test] -fn update_order_consolidates_reserve_decrease_when_asset_out_fee_currency() { +fn update_order_works_with_order_decrease() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, - CurrencyId::ForeignAsset(0), - CurrencyId::Native, - 10, - 2, - 10 + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; - assert_ok!(OrderBook::update_order(ACCOUNT_0, order_id, 10, 1, 10)); + assert_ok!(OrderBook::update_order( + ACCOUNT_0, + order_id, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(1u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); assert_eq!( Orders::::get(order_id), Ok(Order { order_id: order_id, placing_account: ACCOUNT_0, - asset_out_id: CurrencyId::Native, - asset_in_id: CurrencyId::ForeignAsset(0), - buy_amount: 10, - initial_buy_amount: 10, - price: 1, - min_fulfillment_amount: 10, - max_sell_amount: 10 + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_integer(1u32).unwrap(), + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 10 * CURRENCY_USDT_DECIMALS }) ); + assert_eq!( + UserOrders::::get(ACCOUNT_0, order_id), + Ok(Order { + order_id: order_id, + placing_account: ACCOUNT_0, + asset_in_id: DEV_AUSD_CURRENCY_ID, + asset_out_id: DEV_USDT_CURRENCY_ID, + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + initial_buy_amount: 15 * CURRENCY_AUSD_DECIMALS, + max_sell_rate: Rate::checked_from_integer(1u32).unwrap(), + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + max_sell_amount: 10 * CURRENCY_USDT_DECIMALS + }) + ); + + // create order reserve assert_eq!( System::events()[0].event, - RuntimeEvent::Balances(pallet_balances::Event::Reserved { + RuntimeEvent::OrmlTokens(orml_tokens::Event::Reserved { + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - amount: 30 + // order create reserve -- 22.5 + amount: 225 * CURRENCY_USDT_DECIMALS / 10 }) ); + assert_eq!( System::events()[2].event, - RuntimeEvent::Balances(pallet_balances::Event::Unreserved { + RuntimeEvent::OrmlTokens(orml_tokens::Event::Unreserved { + currency_id: DEV_USDT_CURRENCY_ID, who: ACCOUNT_0, - // amount decreased of outgoing currency decreased by 10 - amount: 10 + // update reserve to free 12.5 outgoing tokens no longer needed to cover trade. + amount: 125 * CURRENCY_USDT_DECIMALS / 10 }) ); assert_eq!( @@ -715,14 +763,114 @@ fn update_order_consolidates_reserve_decrease_when_asset_out_fee_currency() { RuntimeEvent::OrderBook(Event::OrderUpdated { order_id, account: ACCOUNT_0, - buy_amount: 10, - min_fulfillment_amount: 10, - sell_price_limit: 1 + buy_amount: 10 * CURRENCY_AUSD_DECIMALS, + min_fullfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, + sell_rate_limit: Rate::checked_from_integer(1u32).unwrap() }) ); }) } +#[test] +fn update_order_requires_min_buy() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_err!( + OrderBook::update_order( + ACCOUNT_0, + order_id, + 1 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(1u32).unwrap(), + 1 * CURRENCY_AUSD_DECIMALS + ), + Error::::InsufficientOrderSize + ); + }) +} + +#[test] +fn update_order_requires_non_zero_min_fulfillment() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_err!( + OrderBook::update_order( + ACCOUNT_0, + order_id, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(1u32).unwrap(), + 0 + ), + Error::::InvalidMinimumFulfillment + ); + }) +} + +#[test] +fn update_order_min_fulfillment_cannot_be_less_than_buy() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_err!( + OrderBook::update_order( + ACCOUNT_0, + order_id, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(1u32).unwrap(), + 15 * CURRENCY_AUSD_DECIMALS, + ), + Error::::InvalidBuyAmount + ); + }) +} + +#[test] +fn update_order_requires_non_zero_price() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_err!( + OrderBook::update_order( + ACCOUNT_0, + order_id, + 10 * CURRENCY_AUSD_DECIMALS, + Rate::zero(), + 15 * CURRENCY_AUSD_DECIMALS, + ), + Error::::InvalidMaxPrice + ); + }) +} + pub fn get_account_orders( account_id: ::AccountId, ) -> Result::OrderIdNonce, OrderOf)>, Error> diff --git a/pallets/order-book/src/weights.rs b/pallets/order-book/src/weights.rs index 08aa75169d..d194f3104b 100644 --- a/pallets/order-book/src/weights.rs +++ b/pallets/order-book/src/weights.rs @@ -13,13 +13,14 @@ pub use frame_support::weights::Weight; pub trait WeightInfo { - fn create_order_v1() -> Weight; + fn create_order() -> Weight; fn user_cancel_order() -> Weight; + fn user_update_order() -> Weight; fn fill_order_full() -> Weight; } impl WeightInfo for () { - fn create_order_v1() -> Weight { + fn create_order() -> Weight { Weight::zero() } @@ -27,6 +28,10 @@ impl WeightInfo for () { Weight::zero() } + fn user_update_order() -> Weight { + Weight::zero() + } + fn fill_order_full() -> Weight { Weight::zero() } diff --git a/pallets/rewards/src/lib.rs b/pallets/rewards/src/lib.rs index bceda8a053..04d83b1d2f 100644 --- a/pallets/rewards/src/lib.rs +++ b/pallets/rewards/src/lib.rs @@ -143,24 +143,12 @@ pub mod pallet { pub struct Pallet(_); #[pallet::genesis_config] - pub struct GenesisConfig, I: 'static = ()> - where - BalanceOf: MaybeSerializeDeserialize, - { - pub currency_id: T::CurrencyId, - pub amount: BalanceOf, - } + pub struct GenesisConfig, I: 'static = ()>(core::marker::PhantomData<(T, I)>); #[cfg(feature = "std")] - impl, I: 'static> Default for GenesisConfig - where - BalanceOf: MaybeSerializeDeserialize, - { + impl, I: 'static> Default for GenesisConfig { fn default() -> Self { - Self { - currency_id: Default::default(), - amount: Default::default(), - } + Self(core::marker::PhantomData) } } @@ -171,9 +159,9 @@ pub mod pallet { { fn build(&self) { T::Currency::mint_into( - self.currency_id, + T::RewardCurrency::get(), &T::PalletId::get().into_account_truncating(), - self.amount, + T::Currency::minimum_balance(T::RewardCurrency::get()), ) .expect("Should not fail to mint ED for rewards sovereign pallet account"); } diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index b22d581620..64bd23e3ed 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "altair-runtime" -version = "0.10.28" +version = "0.10.30" authors = ["Centrifuge "] edition = "2021" build = "build.rs" @@ -119,6 +119,7 @@ pallet-investments = { path = "../../pallets/investments", default-features = fa pallet-keystore = { path = "../../pallets/keystore", default-features = false } pallet-liquidity-pools = { path = "../../pallets/liquidity-pools", default-features = false } pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway", default-features = false } +pallet-liquidity-rewards = { path = "../../pallets/liquidity-rewards", default-features = false } pallet-loans = { path = "../../pallets/loans", default-features = false } pallet-migration-manager = { path = "../../pallets/migration", default-features = false } pallet-nft-sales = { path = "../../pallets/nft-sales", default-features = false } @@ -177,6 +178,7 @@ std = [ "pallet-collective/std", "pallet-liquidity-pools/std", "pallet-liquidity-pools-gateway/std", + "pallet-liquidity-rewards/std", "pallet-crowdloan-claim/std", "pallet-crowdloan-reward/std", "pallet-data-collector/std", @@ -265,6 +267,7 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-liquidity-pools/runtime-benchmarks", "pallet-liquidity-pools-gateway/runtime-benchmarks", + "pallet-liquidity-rewards/runtime-benchmarks", "pallet-crowdloan-claim/runtime-benchmarks", "pallet-crowdloan-reward/runtime-benchmarks", "pallet-data-collector/runtime-benchmarks", @@ -352,6 +355,7 @@ try-runtime = [ "pallet-collective/try-runtime", "pallet-liquidity-pools/try-runtime", "pallet-liquidity-pools-gateway/try-runtime", + "pallet-liquidity-rewards/try-runtime", "pallet-crowdloan-claim/try-runtime", "pallet-crowdloan-reward/try-runtime", "pallet-data-collector/try-runtime", diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 754fb4699e..a53b8be55c 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -124,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("altair"), impl_name: create_runtime_str!("altair"), authoring_version: 1, - spec_version: 1028, + spec_version: 1030, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1192,13 +1192,13 @@ impl cumulus_pallet_dmp_queue::Config for Runtime { // Block Rewards -frame_support::parameter_types! { +parameter_types! { // BlockRewards have exactly one group and currency #[derive(scale_info::TypeInfo)] pub const SingleCurrencyMovement: u32 = 1; #[derive(scale_info::TypeInfo, Debug, PartialEq, Eq, Clone)] pub const MaxChangesPerEpoch: u32 = 50; - pub const RewardsPalletId: PalletId = cfg_types::ids::BLOCK_REWARDS_PALLET_ID; + pub const BlockRewardsPalletId: PalletId = cfg_types::ids::BLOCK_REWARDS_PALLET_ID; pub const RewardCurrency: CurrencyId = CurrencyId::Native; } @@ -1206,7 +1206,7 @@ impl pallet_rewards::Config for Runtime { type Currency = Tokens; type CurrencyId = CurrencyId; type GroupId = u32; - type PalletId = RewardsPalletId; + type PalletId = BlockRewardsPalletId; type RewardCurrency = RewardCurrency; // Must not change this to ensure block rewards are minted type RewardIssuance = @@ -1220,7 +1220,7 @@ impl pallet_rewards::Config for Runtime { type RuntimeEvent = RuntimeEvent; } -frame_support::parameter_types! { +parameter_types! { pub const BlockRewardCurrency: CurrencyId = CurrencyId::Staking(StakingCurrency::BlockRewards); pub const StakeAmount: Balance = cfg_types::consts::rewards::DEFAULT_COLLATOR_STAKE; pub const CollatorGroupId: u32 = cfg_types::ids::COLLATOR_GROUP_ID; @@ -1247,6 +1247,52 @@ impl pallet_block_rewards::Config for Runtime { type WeightInfo = weights::pallet_block_rewards::WeightInfo; } +// Liquidity rewards + +parameter_types! { + #[derive(scale_info::TypeInfo)] + pub const MaxCurrencyMovements: u32 = 50; + #[derive(scale_info::TypeInfo)] + pub const MaxGroups: u32 = 20; + pub const LiquidityRewardsPalletId: PalletId = cfg_types::ids::LIQUIDITY_REWARDS_PALLET_ID; + pub const InitialEpochDuration: Moment = SECONDS_PER_MINUTE * 1000; // 1 min in milliseconds +} + +impl pallet_rewards::mechanism::gap::Config for Runtime { + type Balance = Balance; + type DistributionId = u32; + type IBalance = IBalance; + type MaxCurrencyMovements = MaxCurrencyMovements; + type Rate = FixedI128; +} + +impl pallet_liquidity_rewards::Config for Runtime { + type AdminOrigin = EnsureRootOr; + type Balance = Balance; + type CurrencyId = CurrencyId; + type GroupId = u32; + type InitialEpochDuration = InitialEpochDuration; + type MaxChangesPerEpoch = MaxChangesPerEpoch; + type MaxGroups = MaxGroups; + type Rewards = LiquidityRewardsBase; + type RuntimeEvent = RuntimeEvent; + type Timer = Timestamp; + type Weight = u64; + type WeightInfo = weights::pallet_liquidity_rewards::WeightInfo; +} + +impl pallet_rewards::Config for Runtime { + type Currency = Tokens; + type CurrencyId = CurrencyId; + type GroupId = u32; + type PalletId = LiquidityRewardsPalletId; + type RewardCurrency = RewardCurrency; + type RewardIssuance = + pallet_rewards::issuance::MintReward; + type RewardMechanism = GapRewardMechanism; + type RuntimeEvent = RuntimeEvent; +} + // PoolSystem & Loans parameter_types! { @@ -1794,8 +1840,11 @@ construct_runtime!( PriceCollector: pallet_data_collector::{Pallet, Storage} = 107, LiquidityPools: pallet_liquidity_pools::{Pallet, Call, Storage, Event} = 108, LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 109, - OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 110, - ForeignInvestments: pallet_foreign_investments::{Pallet, Storage, Event} = 111, + LiquidityRewardsBase: pallet_rewards::::{Pallet, Storage, Event, Config} = 110, + LiquidityRewards: pallet_liquidity_rewards::{Pallet, Call, Storage, Event} = 111, + GapRewardMechanism: pallet_rewards::mechanism::gap = 112, + OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 113, + ForeignInvestments: pallet_foreign_investments::{Pallet, Storage, Event} = 114, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, @@ -1858,7 +1907,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - migrations::UpgradeAltair1028, + migrations::UpgradeAltair1030, >; impl fp_self_contained::SelfContainedCall for RuntimeCall { @@ -2250,17 +2299,40 @@ impl_runtime_apis! { } fn create( - _from: H160, - _data: Vec, - _value: U256, - _gas_limit: U256, - _max_fee_per_gas: Option, - _max_priority_fee_per_gas: Option, - _nonce: Option, - _estimate: bool, - _access_list: Option)>>, + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, ) -> Result { - Err(sp_runtime::DispatchError::Other("Creating contracts is not currently supported")) + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + let validate = true; + let evm_config = config.as_ref().unwrap_or_else(|| ::config()); + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + evm_config, + ).map_err(|err| err.error.into()) } fn current_transaction_statuses() -> Option> { diff --git a/runtime/altair/src/migrations.rs b/runtime/altair/src/migrations.rs index 0bc7018f56..849b5e2665 100644 --- a/runtime/altair/src/migrations.rs +++ b/runtime/altair/src/migrations.rs @@ -19,12 +19,37 @@ use sp_std::vec::Vec; use crate::Runtime; -pub type UpgradeAltair1028 = ( +/// The migration set for Altair 1030 @ Kusama. It includes all the migrations +/// that have to be applied on that chain, which includes migrations that have +/// already been executed on Algol (1028 & 1029). +#[cfg(not(feature = "testnet-runtime"))] +pub type UpgradeAltair1030 = ( asset_registry::CrossChainTransferabilityMigration, orml_tokens_migration::CurrencyIdRefactorMigration, pool_system::MigrateAUSDPools, runtime_common::migrations::nuke::Migration, runtime_common::migrations::nuke::Migration, + pallet_rewards::migrations::new_instance::FundExistentialDeposit< + crate::Runtime, + pallet_rewards::Instance2, + crate::NativeToken, + crate::ExistentialDeposit, + >, +); + +/// The Upgrade set for Algol - it excludes the migrations already executed in +/// the side releases that only landed on Algol (1028 & 1029) but not yet on +/// Altair. +#[cfg(feature = "testnet-runtime")] +pub type UpgradeAltair1030 = ( + runtime_common::migrations::nuke::Migration, + runtime_common::migrations::nuke::Migration, + pallet_rewards::migrations::new_instance::FundExistentialDeposit< + crate::Runtime, + pallet_rewards::Instance2, + crate::NativeToken, + crate::ExistentialDeposit, + >, ); const DEPRECATED_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::AUSD; @@ -58,7 +83,7 @@ mod asset_registry { impl OnRuntimeUpgrade for CrossChainTransferabilityMigration { fn on_runtime_upgrade() -> Weight { - if VERSION.spec_version > 1028 { + if VERSION.spec_version > 1030 { return Weight::zero(); } diff --git a/runtime/altair/src/weights/mod.rs b/runtime/altair/src/weights/mod.rs index 33f0831ef5..d361991a78 100644 --- a/runtime/altair/src/weights/mod.rs +++ b/runtime/altair/src/weights/mod.rs @@ -23,6 +23,7 @@ pub mod pallet_fees; pub mod pallet_identity; pub mod pallet_interest_accrual; pub mod pallet_keystore; +pub mod pallet_liquidity_rewards; pub mod pallet_loans; pub mod pallet_migration_manager; pub mod pallet_multisig; diff --git a/runtime/altair/src/weights/pallet_liquidity_rewards.rs b/runtime/altair/src/weights/pallet_liquidity_rewards.rs new file mode 100644 index 0000000000..58b8b1f92a --- /dev/null +++ b/runtime/altair/src/weights/pallet_liquidity_rewards.rs @@ -0,0 +1,37 @@ +//! File pending to be auto-generated + +use frame_support::weights::Weight; +pub struct WeightInfo(sp_std::marker::PhantomData); +impl pallet_liquidity_rewards::WeightInfo for WeightInfo { + fn on_initialize(_: u32, _: u32, _: u32) -> Weight { + Weight::zero() + } + + fn stake() -> Weight { + Weight::zero() + } + + fn unstake() -> Weight { + Weight::zero() + } + + fn claim_reward() -> Weight { + Weight::zero() + } + + fn set_distributed_reward() -> Weight { + Weight::zero() + } + + fn set_epoch_duration() -> Weight { + Weight::zero() + } + + fn set_group_weight() -> Weight { + Weight::zero() + } + + fn set_currency_group() -> Weight { + Weight::zero() + } +} diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index b5f772b1fe..9682890c8a 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -62,7 +62,7 @@ use orml_traits::{currency::MutationHooks, parameter_type_with_key}; use pallet_anchors::AnchorData; pub use pallet_balances::Call as BalancesCall; use pallet_collective::{EnsureMember, EnsureProportionAtLeast, EnsureProportionMoreThan}; -use pallet_ethereum::{Transaction as EthereumTransaction, TransactionAction}; +use pallet_ethereum::Transaction as EthereumTransaction; use pallet_evm::{Account as EVMAccount, FeeCalculator, Runner}; use pallet_investments::OrderType; use pallet_pool_system::{ @@ -89,9 +89,7 @@ use sp_runtime::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, - }, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, FixedI128, Perbill, Permill, Perquintill, }; use sp_std::prelude::*; @@ -108,12 +106,9 @@ mod migrations; mod weights; pub mod xcm; +use runtime_common::fees::{DealWithFees, WeightToFee}; /// common types for the runtime. pub use runtime_common::*; -use runtime_common::{ - evm::GetTransactionAction, - fees::{DealWithFees, WeightToFee}, -}; pub use crate::xcm::*; @@ -1843,77 +1838,6 @@ pub type Executive = frame_executive::Executive< migrations::UpgradeCentrifuge1020, >; -impl fp_self_contained::SelfContainedCall for RuntimeCall { - type SignedInfo = H160; - - fn is_self_contained(&self) -> bool { - match self { - RuntimeCall::Ethereum(call) => call.is_self_contained(), - _ => false, - } - } - - // This is the only method here which is not a simple passthrough - // to `pallet_ethereum`. We additionally unpack the included - // Ethereum transaction in order to filter out contract creation - // calls. - fn check_self_contained(&self) -> Option> { - match self { - RuntimeCall::Ethereum(call) => match call { - pallet_ethereum::Call::transact { transaction } - if transaction.action() == TransactionAction::Create => - { - Some(Err(TransactionValidityError::Invalid( - InvalidTransaction::Call, - ))) - } - _ => call.check_self_contained(), - }, - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option> { - match self { - RuntimeCall::Ethereum(call) => { - call.pre_dispatch_self_contained(info, dispatch_info, len) - } - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - match self { - call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { - Some(call.dispatch(RuntimeOrigin::from( - pallet_ethereum::RawOrigin::EthereumTransaction(info), - ))) - } - _ => None, - } - } -} - pub struct TransactionConverter; impl fp_rpc::ConvertTransaction for TransactionConverter { @@ -2220,17 +2144,40 @@ impl_runtime_apis! { } fn create( - _from: H160, - _data: Vec, - _value: U256, - _gas_limit: U256, - _max_fee_per_gas: Option, - _max_priority_fee_per_gas: Option, - _nonce: Option, - _estimate: bool, - _access_list: Option)>>, + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, ) -> Result { - Err(sp_runtime::DispatchError::Other("Creating contracts is not currently supported")) + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + let validate = true; + let evm_config = config.as_ref().unwrap_or_else(|| ::config()); + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + evm_config, + ).map_err(|err| err.error.into()) } fn current_transaction_statuses() -> Option> { @@ -2445,3 +2392,65 @@ cumulus_pallet_parachain_system::register_validate_block! { BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, CheckInherents = CheckInherents, } + +impl fp_self_contained::SelfContainedCall for RuntimeCall { + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + // This is the only method here which is not a simple passthrough + // to `pallet_ethereum`. We additionally unpack the included + // Ethereum transaction in order to filter out contract creation + // calls. + fn check_self_contained(&self) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => { + call.pre_dispatch_self_contained(info, dispatch_info, len) + } + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => { + Some(call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info), + ))) + } + _ => None, + } + } +} diff --git a/runtime/common/src/migrations/nuke.rs b/runtime/common/src/migrations/nuke.rs index 65b2dc1cf0..c37023f997 100644 --- a/runtime/common/src/migrations/nuke.rs +++ b/runtime/common/src/migrations/nuke.rs @@ -113,7 +113,7 @@ where ); ensure!( - !unhashed::contains_prefixed_key(&pallet_prefix::()), + !contains_prefixed_key_skip_storage_version::(&pallet_prefix::()), "Pallet prefix still exists!" ); @@ -124,3 +124,19 @@ where fn pallet_prefix() -> [u8; 16] { sp_io::hashing::twox_128(Pallet::name().as_bytes()) } + +pub fn contains_prefixed_key_skip_storage_version(prefix: &[u8]) -> bool { + let mut next_key = prefix.to_vec(); + loop { + match sp_io::storage::next_key(&next_key) { + // We catch the storage version if it is found. + // If we catch another key first, the trie contains keys that are not the + // the storage version. We check the prefix and break the loop. + Some(key) if key == StorageVersion::storage_key::() => next_key = key, + Some(key) => break key.starts_with(prefix), + None => { + break false; + } + } + } +} diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 0b321211ec..372d7e5b04 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1759,7 +1759,7 @@ impl< } } -frame_support::parameter_types! { +parameter_types! { pub const RewardsPalletId: PalletId = cfg_types::ids::BLOCK_REWARDS_PALLET_ID; pub const RewardCurrency: CurrencyId = CurrencyId::Native; #[derive(scale_info::TypeInfo)] @@ -1806,7 +1806,7 @@ impl pallet_liquidity_rewards::Config for Runtime { type WeightInfo = (); } -frame_support::parameter_types! { +parameter_types! { // BlockRewards have exactly one group and currency #[derive(scale_info::TypeInfo)] pub const SingleCurrencyMovement: u32 = 1; @@ -1829,7 +1829,7 @@ impl pallet_rewards::Config for Runtime { type RuntimeEvent = RuntimeEvent; } -frame_support::parameter_types! { +parameter_types! { pub const BlockRewardCurrency: CurrencyId = CurrencyId::Staking(BlockRewardsCurrency); pub const StakeAmount: Balance = cfg_types::consts::rewards::DEFAULT_COLLATOR_STAKE; pub const CollatorGroupId: u32 = cfg_types::ids::COLLATOR_GROUP_ID; @@ -1868,23 +1868,46 @@ impl pallet_transfer_allowlist::Config for Runtime { } parameter_types! { - pub const OrderBookCreationFeeKey: FeeKey = FeeKey::OrderBookOrderCreation; pub const OrderPairVecSize: u32 = 1_000_000u32; } +// Minimum order amounts for orderbook orders v1 implementation. +// This will be replaced by runtime specifiable minimum, +// which will likely be set by governance. +const DEV_USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); +const DEV_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); +const DEV_USDT_DECIMALS: u128 = 1_000_000; +const DEV_AUSD_DECIMALS: u128 = 1_000_000_000_000; +const DEFAULT_DEV_MIN_ORDER: u128 = 5; +const MIN_DEV_USDT_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * DEV_USDT_DECIMALS; +const MIN_DEV_AUSD_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * DEV_AUSD_DECIMALS; +const MIN_DEV_NATIVE_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * CFG; + +parameter_type_with_key! { + pub MinimumOrderAmount: |pair: (CurrencyId, CurrencyId)| -> Option { + match pair { + (CurrencyId::Native, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_AUSD_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_AUSD_ORDER), + (CurrencyId::Native, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_USDT_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_USDT_ORDER), + (DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_AUSD_ORDER), + (DEV_USDT_CURRENCY_ID, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_USDT_ORDER), + _ => None + } + }; +} + impl pallet_order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = OrmlAssetRegistry; - type FeeCurrencyId = NativeToken; - type Fees = Fees; - type ForeignCurrencyBalance = Balance; + type Balance = Balance; type FulfilledOrderHook = ForeignInvestments; - type OrderFeeKey = OrderBookCreationFeeKey; + type MinimumOrderAmount = MinimumOrderAmount; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; - type ReserveCurrency = Balances; type RuntimeEvent = RuntimeEvent; - type TradeableAsset = OrmlTokens; + type SellRatio = Rate; + type TradeableAsset = Tokens; type Weights = weights::pallet_order_book::WeightInfo; } diff --git a/runtime/development/src/weights/pallet_order_book.rs b/runtime/development/src/weights/pallet_order_book.rs index 39ad8d28d3..faa9a46dab 100644 --- a/runtime/development/src/weights/pallet_order_book.rs +++ b/runtime/development/src/weights/pallet_order_book.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_order_book` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Theas-MacBook-Pro.local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 @@ -31,73 +31,78 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_order_book`. pub struct WeightInfo(PhantomData); impl pallet_order_book::WeightInfo for WeightInfo { + /// Storage: OrderBook OrderIdNonceStore (r:1 w:1) + /// Proof: OrderBook OrderIdNonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) - /// Storage: OrderBook NonceStore (r:1 w:1) - /// Proof: OrderBook NonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook Orders (r:0 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) - fn create_order_v1() -> Weight { + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn create_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1585` - // Estimated: `32017313` - // Minimum execution time: 57_000 nanoseconds. - Weight::from_parts(58_000_000, 32017313) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `1150` + // Estimated: `8011752` + // Minimum execution time: 43_000 nanoseconds. + Weight::from_parts(44_000_000, 8011752) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: OrderBook Orders (r:1 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:1 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn user_update_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1659` + // Estimated: `14575` + // Minimum execution time: 41_000 nanoseconds. + Weight::from_parts(41_000_000, 14575) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn user_cancel_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1570` - // Estimated: `32012984` - // Minimum execution time: 49_000 nanoseconds. - Weight::from_parts(52_000_000, 32012984) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `1083` + // Estimated: `8007810` + // Minimum execution time: 32_000 nanoseconds. + Weight::from_parts(33_000_000, 8007810) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: OrderBook Orders (r:1 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) - /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) - /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:4 w:4) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) + /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn fill_order_full() -> Weight { // Proof Size summary in bytes: - // Measured: `2449` - // Estimated: `32030798` - // Minimum execution time: 92_000 nanoseconds. - Weight::from_parts(93_000_000, 32030798) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `1669` + // Estimated: `8020828` + // Minimum execution time: 70_000 nanoseconds. + Weight::from_parts(71_000_000, 8020828) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } } diff --git a/src/chain_spec.rs b/src/chain_spec.rs index a5e4a8cdbf..b87d4a24fe 100644 --- a/src/chain_spec.rs +++ b/src/chain_spec.rs @@ -653,10 +653,7 @@ fn centrifuge_genesis( collator_reward: 8_325 * MILLI_CFG, total_reward: 10_048 * CFG, }, - block_rewards_base: centrifuge_runtime::BlockRewardsBaseConfig { - currency_id: CurrencyId::Native, - amount: centrifuge_runtime::ExistentialDeposit::get(), - }, + block_rewards_base: Default::default(), base_fee: Default::default(), evm_chain_id: development_runtime::EVMChainIdConfig { chain_id: chain_id.into(), @@ -745,10 +742,7 @@ fn altair_genesis( collator_reward: 98_630 * MILLI_AIR, total_reward: 98_630 * MILLI_AIR * 100, }, - block_rewards_base: altair_runtime::BlockRewardsBaseConfig { - currency_id: CurrencyId::Native, - amount: altair_runtime::ExistentialDeposit::get(), - }, + block_rewards_base: Default::default(), collator_allowlist: Default::default(), session: altair_runtime::SessionConfig { keys: initial_authorities @@ -774,6 +768,7 @@ fn altair_genesis( }, ethereum: Default::default(), evm: Default::default(), + liquidity_rewards_base: Default::default(), } } @@ -931,14 +926,8 @@ fn development_genesis( }, ethereum: Default::default(), evm: Default::default(), - block_rewards_base: development_runtime::BlockRewardsBaseConfig { - currency_id: CurrencyId::Native, - amount: development_runtime::ExistentialDeposit::get(), - }, - liquidity_rewards_base: development_runtime::LiquidityRewardsBaseConfig { - currency_id: CurrencyId::Native, - amount: development_runtime::ExistentialDeposit::get(), - }, + block_rewards_base: Default::default(), + liquidity_rewards_base: Default::default(), } } From a99ccad027007e6434340de2bd14125419f8d8d8 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 24 Aug 2023 17:20:09 +0200 Subject: [PATCH 56/96] feat: add order pair existence check --- libs/traits/src/lib.rs | 10 ++ pallets/foreign-investments/src/impls/mod.rs | 44 +++++---- pallets/foreign-investments/src/lib.rs | 50 +++++----- pallets/liquidity-pools/src/inbound.rs | 11 ++- pallets/liquidity-pools/src/lib.rs | 18 ++-- pallets/order-book/src/lib.rs | 23 +++++ pallets/order-book/src/tests.rs | 27 ++++++ runtime/altair/src/lib.rs | 50 +++++++--- .../altair/src/weights/pallet_order_book.rs | 93 ++++++++++--------- runtime/development/src/lib.rs | 13 ++- 10 files changed, 217 insertions(+), 122 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 565c95af42..10e3810b5d 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -560,6 +560,16 @@ pub trait TokenSwaps { /// Check if the order is still active. fn is_active(order: Self::OrderId) -> bool; + + /// Check whether there already exist orders for the given trading pair. + fn order_pair_exists(currency_in: Self::CurrencyId, currency_out: Self::CurrencyId) -> bool; + + /// Check whether there already exist counter orders for the given trading + /// pair against which could be traded. + fn counter_order_pair_exists( + currency_in: Self::CurrencyId, + currency_out: Self::CurrencyId, + ) -> bool; } /// Trait to transmit a change of status for anything uniquely identifiable. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 94d8ea9fa0..a9ebbaa789 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -13,8 +13,8 @@ #![allow(clippy::map_identity)] use cfg_traits::{ - investments::{ForeignInvestment, Investment, InvestmentCollector}, - SimpleCurrencyConversion, StatusNotificationHook, TokenSwaps, + investments::{ForeignInvestment, Investment, InvestmentCollector, TrancheCurrency}, + PoolInspect, SimpleCurrencyConversion, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, @@ -337,26 +337,20 @@ impl ForeignInvestment for Pallet { } fn accepted_payment_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { - // TODO(future): If this returns false, we should add a mechanism which checks - // whether `currency` can be swapped into an accepted payment currency. - // - // This requires - // * Querying all accepted payment currencies of an investment - // * Checking whether there are orders from `currency` into an accepted - // payment currency - T::Investment::accepted_payment_currency(investment_id, currency) + if T::Investment::accepted_payment_currency(investment_id, currency) { + true + } else { + T::PoolInspect::currency_for(investment_id.of_pool()) + .map(|pool_currency| { + // TODO(@review): Or just `order_pair_exists`? + T::TokenSwaps::counter_order_pair_exists(currency, pool_currency) + }) + .unwrap_or(false) + } } fn accepted_payout_currency(investment_id: T::InvestmentId, currency: T::CurrencyId) -> bool { - // TODO(future): If this returns false, we should add a mechanism which checks - // whether any of the accepted `payout` currencies can be swapped into - // `currency`. - // - // This requires - // * Querying all accepted payout currencies of an investment - // * Checking whether there are orders from an accepted payout currency into - // `currency` - T::Investment::accepted_payout_currency(investment_id, currency) + Self::accepted_payment_currency(investment_id, currency) } } @@ -861,8 +855,10 @@ impl Pallet { who.clone(), swap_order_id, swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), + // The max accepted sell rate is independent of the asset type for now + T::DefaultTokenSellRate::get(), + // The minimum fulfillment must be everything + swap.amount, )?; ForeignInvestmentInfo::::insert( swap_order_id, @@ -879,8 +875,10 @@ impl Pallet { swap.currency_out, swap.currency_in, swap.amount, - T::DefaultTokenSwapSellPriceLimit::get(), - T::DefaultTokenMinFulfillmentAmount::get(), + // The max accepted sell rate is independent of the asset type for now + T::DefaultTokenSellRate::get(), + // The minimum fulfillment must be everything + swap.amount, )?; TokenSwapOrderIds::::insert(who, investment_id, swap_order_id); ForeignInvestmentInfo::::insert( diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 4ff00aae7c..a0e2b66801 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -34,7 +34,7 @@ pub type ForeignInvestmentInfoOf = cfg_types::investments::ForeignInvestmentI pub mod pallet { use cfg_traits::{ investments::{Investment as InvestmentT, InvestmentCollector, TrancheCurrency}, - StatusNotificationHook, TokenSwaps, + PoolInspect, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, @@ -119,30 +119,28 @@ pub mod pallet { Result = CollectedAmount, >; - /// The default sell price limit for token swaps which defines the - /// lowest acceptable buy price. - /// - /// NOTE: Can be removed once we implement a - /// more sophisticated swap price discovery. - // TODO(@review): Since we will only support stable coins from the - // beginning, a global default value could be feasible or do we want to - // have better granularity? - #[pallet::constant] - type DefaultTokenSwapSellPriceLimit: Get; + /// Type for price ratio for cost of incoming currency relative to + /// outgoing + type Rate: Parameter + + Member + + sp_runtime::FixedPointNumber + + sp_runtime::traits::EnsureMul + + sp_runtime::traits::EnsureDiv + + MaybeSerializeDeserialize + + TypeInfo + + MaxEncodedLen; - /// The default minimum fulfillment amount for token swaps. + /// The default sell rate for token swaps which will be applied to all + /// swaps created/updated through Foreign Investments. /// - /// TODO(@review): Since we will only support stable coins from the - /// beginning, a global default value could be feasible or do we want to - /// have better granularity? + /// Example: Say this rate is set to 3/2, then the incoming currency + /// should never cost more than 1.5 of the outgoing currency. /// - /// NOTE: Can be removed once we implement a more sophisticated swap - /// price discovery. - // TODO(@review): Since we will only support stable coins from the - // beginning, a global default value could be feasible or do we want to - // have better granularity? + /// NOTE: Can be removed once we implement a + /// more sophisticated swap price discovery. For now, this should be set + /// to one. #[pallet::constant] - type DefaultTokenMinFulfillmentAmount: Get; + type DefaultTokenSellRate: Get; /// The token swap order identifying type type TokenSwapOrderId: Parameter @@ -160,6 +158,7 @@ pub mod pallet { CurrencyId = Self::CurrencyId, Balance = Self::Balance, OrderId = Self::TokenSwapOrderId, + SellRatio = Self::Rate, >; /// The hook type which acts upon a finalized investment decrement. @@ -191,6 +190,15 @@ pub mod pallet { Currency = Self::CurrencyId, Error = DispatchError, >; + + /// The source of truth for pool currencies. + type PoolInspect: PoolInspect< + Self::AccountId, + Self::CurrencyId, + Rate = Self::Rate, + PoolId = Self::PoolId, + TrancheId = Self::TrancheId, + >; } /// Maps an investor and their `InvestmentId` to the corresponding diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index e6df2e6e6d..d83e7c34e5 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -191,7 +191,7 @@ where sending_domain: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; + let payout_currency = Self::try_get_payout_currency(invest_id.clone(), currency_index)?; // Transfer tranche tokens from `DomainLocator` account of // origination domain @@ -231,7 +231,8 @@ where destination: DomainAddress, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; + let currency_u128 = currency_index.index; + let payout_currency = Self::try_get_payout_currency(invest_id.clone(), currency_index)?; // TODO(@review): This is exactly `amount` as we can only decrement up to the // unprocessed redemption @@ -254,7 +255,7 @@ where pool_id, tranche_id, investor: investor.into(), - currency: currency_index.index, + currency: currency_u128, tranche_tokens_payout, }; @@ -282,8 +283,8 @@ where pool_id, tranche_id, investor, - currency_index, amount, + currency_index, destination, ) } @@ -362,7 +363,7 @@ where currency_index: GeneralCurrencyIndexOf, ) -> DispatchResult { let invest_id: T::TrancheCurrency = Self::derive_invest_id(pool_id, tranche_id)?; - let payout_currency = Self::try_get_payout_currency(invest_id, currency_index)?; + let payout_currency = Self::try_get_payout_currency(invest_id.clone(), currency_index)?; let pool_currency = T::PoolInspect::currency_for(pool_id).ok_or(Error::::PoolNotFound)?; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index d5375c14b8..ca1006d39a 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -697,6 +697,7 @@ pub mod pallet { Ok(()) } + // TODO: Split up, see https://centrifuge.hackmd.io/tKGS5CwqSQeeI3bU1dKUlw#Action-items /// Collect a user's foreign investment as if we had received a /// `CollectInvest` message from another domain. #[pallet::call_index(10)] @@ -706,23 +707,21 @@ pub mod pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - currency: CurrencyIdOf, - destination: DomainAddress, ) -> DispatchResult { ensure_signed(origin)?; - let currency_index = currency.try_into()?; Self::handle_collect_investment( pool_id, tranche_id, investor, - currency_index, - destination, + todo!("query via foreign investments"), + todo!("derive via currency"), )?; Ok(()) } + // TODO: Split up, see https://centrifuge.hackmd.io/tKGS5CwqSQeeI3bU1dKUlw#Action-items /// Collect a user's foreign redemption as if we had received a /// `CollectRedeem` message from another domain. #[pallet::call_index(11)] @@ -732,12 +731,15 @@ pub mod pallet { pool_id: T::PoolId, tranche_id: T::TrancheId, investor: T::AccountId, - currency: CurrencyIdOf, ) -> DispatchResult { ensure_signed(origin)?; - let currency_index = currency.try_into()?; - Self::handle_collect_redemption(pool_id, tranche_id, investor, currency_index)?; + Self::handle_collect_redemption( + pool_id, + tranche_id, + investor, + todo!("query via foreign investments"), + )?; Ok(()) } diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index ccd0e2cab6..adca65a2a8 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -230,6 +230,8 @@ pub mod pallet { /// Map of Vec containing OrderIds of same asset in/out pairs. /// Allows looking up orders available corresponding pairs. + /// + /// NOTE: The key order is (currency_in, currency_out). #[pallet::storage] pub type AssetPairOrders = StorageDoubleMap< _, @@ -699,5 +701,26 @@ pub mod pallet { fn is_active(order: Self::OrderId) -> bool { >::contains_key(order) } + + /// Check whether there already exist orders for the given trading pair. + fn order_pair_exists( + currency_in: Self::CurrencyId, + currency_out: Self::CurrencyId, + ) -> bool { + !AssetPairOrders::::get(currency_in, currency_out) + .len() + .is_zero() + } + + /// Check whether there already exist counter orders for the given + /// trading pair against which could be traded. + fn counter_order_pair_exists( + currency_in: Self::CurrencyId, + currency_out: Self::CurrencyId, + ) -> bool { + !AssetPairOrders::::get(currency_out, currency_in) + .len() + .is_zero() + } } } diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index b7af00135f..0e6ddfb707 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -871,6 +871,33 @@ fn update_order_requires_non_zero_price() { }) } +#[test] +fn order_pair_exists() { + new_test_ext().execute_with(|| { + let currency_in = DEV_AUSD_CURRENCY_ID; + let currency_out = DEV_USDT_CURRENCY_ID; + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + currency_in, + currency_out, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + assert!(OrderBook::order_pair_exists(currency_in, currency_out)); + assert!(OrderBook::counter_order_pair_exists( + currency_out, + currency_in + )); + + assert!(!OrderBook::order_pair_exists(currency_out, currency_in)); + assert!(!OrderBook::counter_order_pair_exists( + currency_in, + currency_out + )); + }) +} + pub fn get_account_orders( account_id: ::AccountId, ) -> Result::OrderIdNonce, OrderOf)>, Error> diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index a53b8be55c..fed5af20d2 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -85,7 +85,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, - Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, + Dispatchable, One, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, DispatchError, DispatchResult, FixedI128, Perbill, Permill, Perquintill, @@ -1386,10 +1386,8 @@ impl pallet_xcm_transactor::Config for Runtime { } parameter_types! { - // TODO(@review): Discuss and refine all of these three parameters - pub const DefaultTokenMinFulfillmentAmount: Balance = 1; - pub const DefaultTokenSwapSellPriceLimit: Balance = 1; - pub ConversionRate: Rate = Rate::from((98, 100)); + pub DefaultTokenSellRate: Rate = Rate::one(); + pub ConversionRate: Rate = Rate::one(); } impl pallet_foreign_investments::Config for Runtime { @@ -1397,14 +1395,15 @@ impl pallet_foreign_investments::Config for Runtime { type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; - type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; - type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; + type DefaultTokenSellRate = DefaultTokenSellRate; type ExecutedCollectRedeemHook = pallet_liquidity_pools::hooks::CollectRedeemHook; type ExecutedDecreaseInvestHook = pallet_liquidity_pools::hooks::DecreaseInvestOrderHook; type Investment = Investments; type InvestmentId = TrancheCurrency; type PoolId = PoolId; + type PoolInspect = PoolSystem; + type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; type TokenSwaps = OrderBook; @@ -1758,23 +1757,46 @@ impl pallet_keystore::pallet::Config for Runtime { } parameter_types! { - pub const OrderBookCreationFeeKey: FeeKey = FeeKey::OrderBookOrderCreation; pub const OrderPairVecSize: u32 = 1_000_000u32; } +// Minimum order amounts for orderbook orders v1 implementation. +// This will be replaced by runtime specifiable minimum, +// which will likely be set by governance. +const DEV_USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); +const DEV_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); +const DEV_USDT_DECIMALS: u128 = 1_000_000; +const DEV_AUSD_DECIMALS: u128 = 1_000_000_000_000; +const DEFAULT_DEV_MIN_ORDER: u128 = 5; +const MIN_DEV_USDT_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * DEV_USDT_DECIMALS; +const MIN_DEV_AUSD_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * DEV_AUSD_DECIMALS; +const MIN_DEV_NATIVE_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * CFG; + +parameter_type_with_key! { + pub MinimumOrderAmount: |pair: (CurrencyId, CurrencyId)| -> Option { + match pair { + (CurrencyId::Native, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_AUSD_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_AUSD_ORDER), + (CurrencyId::Native, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), + (DEV_USDT_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_USDT_ORDER), + (DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID) => Some(MIN_DEV_AUSD_ORDER), + (DEV_USDT_CURRENCY_ID, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_USDT_ORDER), + _ => None + } + }; +} + impl pallet_order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = OrmlAssetRegistry; - type FeeCurrencyId = NativeToken; - type Fees = Fees; - type ForeignCurrencyBalance = Balance; + type Balance = Balance; type FulfilledOrderHook = ForeignInvestments; - type OrderFeeKey = OrderBookCreationFeeKey; + type MinimumOrderAmount = MinimumOrderAmount; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; - type ReserveCurrency = Balances; type RuntimeEvent = RuntimeEvent; - type TradeableAsset = OrmlTokens; + type SellRatio = Rate; + type TradeableAsset = Tokens; type Weights = weights::pallet_order_book::WeightInfo; } diff --git a/runtime/altair/src/weights/pallet_order_book.rs b/runtime/altair/src/weights/pallet_order_book.rs index 39ad8d28d3..faa9a46dab 100644 --- a/runtime/altair/src/weights/pallet_order_book.rs +++ b/runtime/altair/src/weights/pallet_order_book.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_order_book` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-08-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Theas-MacBook-Pro.local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 @@ -31,73 +31,78 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_order_book`. pub struct WeightInfo(PhantomData); impl pallet_order_book::WeightInfo for WeightInfo { + /// Storage: OrderBook OrderIdNonceStore (r:1 w:1) + /// Proof: OrderBook OrderIdNonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) - /// Storage: OrderBook NonceStore (r:1 w:1) - /// Proof: OrderBook NonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook Orders (r:0 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) - fn create_order_v1() -> Weight { + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn create_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1585` - // Estimated: `32017313` - // Minimum execution time: 57_000 nanoseconds. - Weight::from_parts(58_000_000, 32017313) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `1150` + // Estimated: `8011752` + // Minimum execution time: 43_000 nanoseconds. + Weight::from_parts(44_000_000, 8011752) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: OrderBook Orders (r:1 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:1 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn user_update_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1659` + // Estimated: `14575` + // Minimum execution time: 41_000 nanoseconds. + Weight::from_parts(41_000_000, 14575) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn user_cancel_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1570` - // Estimated: `32012984` - // Minimum execution time: 49_000 nanoseconds. - Weight::from_parts(52_000_000, 32012984) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `1083` + // Estimated: `8007810` + // Minimum execution time: 32_000 nanoseconds. + Weight::from_parts(33_000_000, 8007810) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: OrderBook Orders (r:1 w:1) - /// Proof: OrderBook Orders (max_values: None, max_size: Some(234), added: 2709, mode: MaxEncodedLen) - /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) - /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrmlTokens Accounts (r:4 w:4) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) - /// Storage: Fees FeeBalances (r:1 w:0) - /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:1) + /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(32000070), added: 32002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) - /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(274), added: 2749, mode: MaxEncodedLen) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn fill_order_full() -> Weight { // Proof Size summary in bytes: - // Measured: `2449` - // Estimated: `32030798` - // Minimum execution time: 92_000 nanoseconds. - Weight::from_parts(93_000_000, 32030798) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `1669` + // Estimated: `8020828` + // Minimum execution time: 70_000 nanoseconds. + Weight::from_parts(71_000_000, 8020828) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } } diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 372d7e5b04..6817658646 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -104,7 +104,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, - Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, + Dispatchable, One, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, FixedI128, Perbill, Permill, Perquintill, @@ -1574,10 +1574,8 @@ impl orml_asset_registry::Config for Runtime { } parameter_types! { - // TODO(@review): Discuss and refine all of these three parameters - pub const DefaultTokenMinFulfillmentAmount: Balance = 1; - pub const DefaultTokenSwapSellPriceLimit: Balance = 1; - pub ConversionRate: Rate = Rate::from((98, 100)); + pub DefaultTokenSellRate: Rate = Rate::one(); + pub ConversionRate: Rate = Rate::one(); } impl pallet_foreign_investments::Config for Runtime { @@ -1585,14 +1583,15 @@ impl pallet_foreign_investments::Config for Runtime { type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; - type DefaultTokenMinFulfillmentAmount = DefaultTokenMinFulfillmentAmount; - type DefaultTokenSwapSellPriceLimit = DefaultTokenSwapSellPriceLimit; + type DefaultTokenSellRate = DefaultTokenSellRate; type ExecutedCollectRedeemHook = pallet_liquidity_pools::hooks::CollectRedeemHook; type ExecutedDecreaseInvestHook = pallet_liquidity_pools::hooks::DecreaseInvestOrderHook; type Investment = Investments; type InvestmentId = TrancheCurrency; type PoolId = PoolId; + type PoolInspect = PoolSystem; + type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; type TokenSwaps = OrderBook; From f5dd6f36906952d19ceba300c17d571fb50bae29 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 25 Aug 2023 10:22:31 +0200 Subject: [PATCH 57/96] wip: attempt to fix altair compilation --- pallets/foreign-investments/Cargo.toml | 4 + pallets/order-book/Cargo.toml | 86 +++++++++---------- runtime/altair/Cargo.toml | 3 +- runtime/altair/src/lib.rs | 1 + runtime/development/Cargo.toml | 2 +- .../{add_allow.rs => add_allow_upgrade.rs} | 51 ++++++++++- 6 files changed, 95 insertions(+), 52 deletions(-) rename runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/{add_allow.rs => add_allow_upgrade.rs} (93%) diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml index d07585ef4d..4a129a82da 100644 --- a/pallets/foreign-investments/Cargo.toml +++ b/pallets/foreign-investments/Cargo.toml @@ -51,11 +51,15 @@ runtime-benchmarks = [ "cfg-types/runtime-benchmarks", "cfg-primitives/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ "cfg-primitives/try-runtime", "cfg-traits/try-runtime", + "cfg-types/try-runtime", "frame-support/try-runtime", + "frame-system/try-runtime", "sp-runtime/try-runtime", ] diff --git a/pallets/order-book/Cargo.toml b/pallets/order-book/Cargo.toml index 76143e8d6e..5f6dee466a 100644 --- a/pallets/order-book/Cargo.toml +++ b/pallets/order-book/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "pallet-order-book" -description = "Pallet to add order book for currency exchanges. Initially based off Zeitgeist orderbook found here: https://github.com/zeitgeistpm/zeitgeist/tree/main/zrml/orderbook-v1" +description = "Pallet to add order book for currency exchanges. Initially based off Zeitgeist orderbook found here: https://github.com/zeitgeistpm/zeitgeist/tree/main/zrml/orderbook-v1" version = "0.1.0" authors = ["Centrifuge "] -homepage = 'https://centrifuge.io' +homepage = "https://centrifuge.io" license = "LGPL-3.0" -repository = 'https://github.com/centrifuge/centrifuge-chain' +repository = "https://github.com/centrifuge/centrifuge-chain" edition = "2021" [package.metadata.docs.rs] -targets = ['x86_64-unknown-linux-gnu'] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = 'parity-scale-codec', version = '3.0.0', features = ['derive'], default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } @@ -26,9 +26,8 @@ cfg-primitives = { path = "../../libs/primitives", default-features = false } cfg-traits = { path = "../../libs/traits", default-features = false } cfg-types = { path = "../../libs/types", default-features = false } -## Benchmark dependencies -# Orml crates - +# Benchmark dependencies +## Orml crates orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, optional = true, branch = "polkadot-v0.9.38" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } @@ -37,53 +36,50 @@ frame-benchmarking = { git = "https://github.com/paritytech/substrate", default- [dev-dependencies] cfg-mocks = { path = "../../libs/mocks" } cfg-test-utils = { path = "../../libs/test-utils", default-features = true } +pallet-restricted-tokens = { path = "../restricted-tokens", default-features = false } # Orml crates orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = true, branch = "polkadot-v0.9.38" } # Parity crates pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = true, branch = "polkadot-v0.9.38" } -pallet-restricted-tokens = { path = "../restricted-tokens", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", default-features = true, branch = "polkadot-v0.9.38" } xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } [features] -default = ['std'] - -runtime-benchmarks = [ - 'frame-benchmarking/runtime-benchmarks', - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', - 'sp-runtime/runtime-benchmarks', - 'cfg-types/runtime-benchmarks', - 'cfg-traits/runtime-benchmarks', - 'cfg-primitives/runtime-benchmarks', - 'orml-asset-registry/runtime-benchmarks', - 'cfg-mocks/runtime-benchmarks', - 'cfg-test-utils/runtime-benchmarks', - -] - +default = ["std"] std = [ - 'codec/std', - 'frame-support/std', - 'frame-system/std', - 'frame-benchmarking/std', - 'scale-info/std', - 'serde/std', - 'sp-core/std', - 'sp-arithmetic/std', - 'sp-runtime/std', - 'sp-std/std', - 'orml-traits/std', - 'cfg-primitives/std', - 'cfg-types/std', - 'cfg-traits/std', + "codec/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "scale-info/std", + "serde/std", + "sp-core/std", + "sp-arithmetic/std", + "sp-runtime/std", + "sp-std/std", + "orml-traits/std", + "cfg-primitives/std", + "cfg-types/std", + "cfg-traits/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "cfg-types/runtime-benchmarks", + "cfg-traits/runtime-benchmarks", + "cfg-primitives/runtime-benchmarks", + "orml-asset-registry/runtime-benchmarks", + "cfg-mocks/runtime-benchmarks", + "cfg-test-utils/runtime-benchmarks", ] try-runtime = [ - 'frame-support/try-runtime', - 'frame-system/try-runtime', - 'sp-runtime/try-runtime', - 'cfg-primitives/try-runtime', - 'cfg-types/try-runtime', - 'cfg-traits/try-runtime', + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", + "cfg-primitives/try-runtime", + "cfg-types/try-runtime", + "cfg-traits/try-runtime", ] diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index 64bd23e3ed..250b1cf721 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -202,7 +202,6 @@ std = [ "pallet-nft-sales/std", "pallet-order-book/std", "pallet-permissions/std", - "pallet-permissions/std", "moonbeam-relay-encoder/std", "pallet-pool-system/std", "pallet-pool-registry/std", @@ -277,7 +276,7 @@ runtime-benchmarks = [ "pallet-ethereum-transaction/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", - # "pallet-foreign-investments/runtime-benchmarks", + "pallet-foreign-investments/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index fed5af20d2..0701f22d6c 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1760,6 +1760,7 @@ parameter_types! { pub const OrderPairVecSize: u32 = 1_000_000u32; } +// FIXME: Do not merge before discussing this! // Minimum order amounts for orderbook orders v1 implementation. // This will be replaced by runtime specifiable minimum, // which will likely be set by governance. diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index d3d614cd6b..37740b4213 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -300,7 +300,7 @@ runtime-benchmarks = [ "pallet-ethereum-transaction/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", - # "pallet-foreign-investments/runtime-benchmarks", + "pallet-foreign-investments/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", "pallet-keystore/runtime-benchmarks", diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs similarity index 93% rename from runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs rename to runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index afffb4dd32..04e68e0159 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -38,7 +38,7 @@ use cfg_types::{ }; use development_runtime::{ LiquidityPools, OrmlAssetRegistry, Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, - System, + System, TreasuryAccount, XTokens, XcmTransactor, }; use frame_support::{assert_noop, assert_ok}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; @@ -56,9 +56,10 @@ use crate::{ test_net::{Development, Moonbeam, RelayChain, TestNet}, tests::liquidity_pools::setup::{ asset_metadata, create_ausd_pool, create_currency_pool, - enable_liquidity_pool_transferability, investments::default_tranche_id, - liquidity_pools_transferable_multilocation, setup_pre_requirements, DEFAULT_POOL_ID, - DEFAULT_VALIDITY, + enable_liquidity_pool_transferability, get_default_moonbeam_native_token_location, + investments::default_tranche_id, liquidity_pools_transferable_multilocation, + setup_pre_requirements, DEFAULT_BALANCE_GLMR, DEFAULT_MOONBEAM_LOCATION, + DEFAULT_POOL_ID, DEFAULT_VALIDITY, }, }, utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, @@ -594,3 +595,45 @@ fn allow_pool_should_fail() { ); }); } + +#[test] +fn schedule_upgrade() { + use frame_support::traits::fungible::Mutate; + + TestNet::reset(); + + Development::execute_with(|| { + utils::setup_pre_requirements(); + + // Only Root can call `schedule_upgrade` + assert_noop!( + LiquidityPools::schedule_upgrade( + RuntimeOrigin::signed(BOB.into()), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + ), + BadOrigin + ); + + // Failing because the treasury has no funds + assert_noop!( + LiquidityPools::schedule_upgrade(RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, [7; 20]), + pallet_xcm_transactor::Error::::UnableToWithdrawAsset + ); + + // The treasury needs GLRM to cover the fees of sending + // this message + OrmlTokens::deposit( + GLIMMER_CURRENCY_ID, + &TreasuryAccount::get(), + DEFAULT_BALANCE_GLMR, + ); + + // Now it finally works + assert_ok!(LiquidityPools::schedule_upgrade( + RuntimeOrigin::root(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + )); + }); +} From d242cd508dd33b708753ed5bdc37b7d59414603e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 25 Aug 2023 11:00:55 +0200 Subject: [PATCH 58/96] fix: make altair compilable --- Cargo.lock | 1 + pallets/foreign-investments/Cargo.toml | 2 ++ runtime/altair/Cargo.toml | 4 +++- runtime/integration-tests/Cargo.toml | 2 +- .../liquidity_pools/add_allow_upgrade.rs | 21 +++++++++++-------- .../development/tests/liquidity_pools/mod.rs | 2 +- .../non_foreign_investments.rs | 2 +- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c76c4ac74..11ba09c5f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7523,6 +7523,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std", ] [[package]] diff --git a/pallets/foreign-investments/Cargo.toml b/pallets/foreign-investments/Cargo.toml index 4a129a82da..6b9a02c758 100644 --- a/pallets/foreign-investments/Cargo.toml +++ b/pallets/foreign-investments/Cargo.toml @@ -24,6 +24,7 @@ cfg-types = { path = "../../libs/types", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } # Benchmarking dependencies - optional frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } @@ -45,6 +46,7 @@ std = [ "log/std", "scale-info/std", "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "cfg-traits/runtime-benchmarks", diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index 250b1cf721..c001f00c8d 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -54,7 +54,9 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features # frame dependencies frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38", features = [ + "tuples-96", +] } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index 6165eb8253..fab211410d 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -96,8 +96,8 @@ pallet-evm-chain-id = { git = "https://github.com/PureStake/frontier", default-f liquidity-pools-gateway-routers = { path = "../../pallets/liquidity-pools-gateway/routers" } pallet-block-rewards = { path = "../../pallets/block-rewards" } pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction" } -pallet-investments = { path = "../../pallets/investments" } pallet-foreign-investments = { path = "../../pallets/foreign-investments" } +pallet-investments = { path = "../../pallets/investments" } pallet-liquidity-pools = { path = "../../pallets/liquidity-pools" } pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway" } pallet-loans = { path = "../../pallets/loans" } diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index 04e68e0159..36a2c57b79 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -37,10 +37,10 @@ use cfg_types::{ }, }; use development_runtime::{ - LiquidityPools, OrmlAssetRegistry, Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, - System, TreasuryAccount, XTokens, XcmTransactor, + LiquidityPools, OrmlAssetRegistry, OrmlTokens, Permissions, Runtime as DevelopmentRuntime, + RuntimeOrigin, System, TreasuryAccount, XTokens, XcmTransactor, }; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, traits::fungibles::Mutate}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ @@ -62,7 +62,7 @@ use crate::{ DEFAULT_POOL_ID, DEFAULT_VALIDITY, }, }, - utils::{AUSD_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, + utils::{AUSD_CURRENCY_ID, GLMR_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, }; /// NOTE: We can't actually verify that the messages hits the @@ -598,12 +598,9 @@ fn allow_pool_should_fail() { #[test] fn schedule_upgrade() { - use frame_support::traits::fungible::Mutate; - TestNet::reset(); - Development::execute_with(|| { - utils::setup_pre_requirements(); + setup_pre_requirements(); // Only Root can call `schedule_upgrade` assert_noop!( @@ -616,6 +613,12 @@ fn schedule_upgrade() { ); // Failing because the treasury has no funds + // Treasury pays for `Executed*` messages + OrmlTokens::burn_from( + GLMR_CURRENCY_ID, + &TreasuryAccount::get(), + DEFAULT_BALANCE_GLMR, + ); assert_noop!( LiquidityPools::schedule_upgrade(RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, [7; 20]), pallet_xcm_transactor::Error::::UnableToWithdrawAsset @@ -624,7 +627,7 @@ fn schedule_upgrade() { // The treasury needs GLRM to cover the fees of sending // this message OrmlTokens::deposit( - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, &TreasuryAccount::get(), DEFAULT_BALANCE_GLMR, ); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs index 8e6ef17051..7c63daf94e 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs @@ -22,7 +22,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -mod add_allow; +mod add_allow_upgrade; mod foreign_investments; mod non_foreign_investments; mod setup; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 105b3c54d8..8066f81877 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -979,7 +979,7 @@ mod should_fail { amount: 1, }; assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg.clone()), pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); From 2beb562d0d41172440b01ff7203d76ce1f1b7fb7 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 25 Aug 2023 17:45:46 +0200 Subject: [PATCH 59/96] feat: collect hooks --- pallets/foreign-investments/src/errors.rs | 2 + pallets/foreign-investments/src/hooks.rs | 150 ++++++++++ .../foreign-investments/src/impls/invest.rs | 2 +- pallets/foreign-investments/src/impls/mod.rs | 260 ++++++++++-------- .../foreign-investments/src/impls/redeem.rs | 2 +- pallets/foreign-investments/src/lib.rs | 76 ++++- pallets/investments/src/lib.rs | 89 ++++-- pallets/investments/src/mock.rs | 13 + pallets/liquidity-pools/src/hooks.rs | 8 +- pallets/liquidity-pools/src/inbound.rs | 18 +- pallets/liquidity-pools/src/lib.rs | 75 ++--- pallets/pool-registry/src/mock.rs | 12 + pallets/pool-system/src/mock.rs | 12 + runtime/altair/src/lib.rs | 14 +- runtime/centrifuge/Cargo.toml | 4 + runtime/centrifuge/src/lib.rs | 16 +- runtime/development/src/lib.rs | 13 +- .../non_foreign_investments.rs | 7 +- 18 files changed, 550 insertions(+), 223 deletions(-) create mode 100644 pallets/foreign-investments/src/hooks.rs diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index 8ba006ab27..cb9659eb36 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -28,6 +28,8 @@ pub enum InvestError { Collect, /// The investment needs to be collected before it can be updated further. CollectRequired, + /// Attempted to collect an investment which has not been processed yet. + NothingCollected, } #[derive(Encode, Decode, TypeInfo, PalletError)] diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs new file mode 100644 index 0000000000..949e3ac21b --- /dev/null +++ b/pallets/foreign-investments/src/hooks.rs @@ -0,0 +1,150 @@ +// 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 cfg_traits::StatusNotificationHook; +use cfg_types::investments::{ + CollectedAmount, ForeignInvestmentInfo, +}; +use frame_support::transactional; +use sp_runtime::{DispatchError, DispatchResult}; +use sp_std::marker::PhantomData; + +use crate::{ + errors::{InvestError, RedeemError}, + types::{InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason}, + Config, Error, ForeignInvestmentInfo as ForeignInvestmentInfoStorage, InvestmentState, Pallet, + RedemptionState, SwapOf, +}; + +/// The hook struct which acts upon a fulfilled swap order. Depending on the +/// last swap reason, advances either the [`InvestmentState`] or +/// [`RedemptionState`]. +/// +/// Assumes `TokenSwaps` as caller of of the the `notify_status_change` message. +pub struct FulfilledSwapOrderHook(PhantomData); + +// Hook execution for (partially) fulfilled token swaps which should be consumed +// by `TokenSwaps`. +impl StatusNotificationHook for FulfilledSwapOrderHook { + type Error = DispatchError; + type Id = T::TokenSwapOrderId; + type Status = SwapOf; + + #[transactional] + fn notify_status_change( + id: T::TokenSwapOrderId, + status: SwapOf, + ) -> Result<(), DispatchError> { + let info = + ForeignInvestmentInfoStorage::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; + let reason = info + .last_swap_reason + .ok_or(Error::::TokenSwapReasonNotFound)?; + + match reason { + TokenSwapReason::Investment => { + let pre_state = InvestmentState::::get(&info.owner, info.id); + let post_state = pre_state + .transition(InvestTransition::FulfillSwapOrder(status)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(InvestError::FulfillSwapOrder) + })?; + Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) + } + TokenSwapReason::Redemption => { + let pre_state = RedemptionState::::get(&info.owner, info.id); + let post_state = pre_state + .transition(RedeemTransition::FulfillSwapOrder(status)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(RedeemError::FulfillSwapOrder) + })?; + Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) + } + } + } +} + +/// The hook struct which acts upon the collection of a foreign investment. +/// +/// NOTE: Only increments the collected amount and transitions the `InvestState` +/// to update the unprocessed invest amount but does not transfer back the +/// collected amounts. We expect the user do that via +/// `collect_foreign_investment`. +pub struct CollectedInvestmentHook(PhantomData); +impl StatusNotificationHook for CollectedInvestmentHook { + type Error = DispatchError; + type Id = ForeignInvestmentInfo; + type Status = CollectedAmount; + + #[transactional] + fn notify_status_change( + id: ForeignInvestmentInfo, + status: CollectedAmount, + ) -> DispatchResult { + let ForeignInvestmentInfo { + id: investment_id, + owner: investor, + .. + } = id; + let pre_state = InvestmentState::::get(&investor, investment_id); + + // Exit early if there is no foreign investment + if pre_state == InvestState::NoState { + return Ok(()); + } + + Pallet::::denote_collected_investment(&investor, investment_id, status)?; + + Ok(()) + } +} + +/// The hook struct which acts upon a finalized redemption collection. +/// +/// NOTE: Only increments the collected amount and transitions the `RedeemState` +/// to update the unprocessed redeem amount but does not transfer back the +/// collected amounts. We expect the user do via +/// `collect_foreign_redemption`. + +pub struct CollectedRedemptionHook(PhantomData); +impl StatusNotificationHook for CollectedRedemptionHook { + type Error = DispatchError; + type Id = ForeignInvestmentInfo; + type Status = CollectedAmount; + + #[transactional] + fn notify_status_change( + id: ForeignInvestmentInfo, + status: CollectedAmount, + ) -> DispatchResult { + let ForeignInvestmentInfo { + id: investment_id, + owner: investor, + .. + } = id; + let pre_state = RedemptionState::::get(&investor, investment_id); + + // Exit early if there is no foreign redemption + if pre_state == RedeemState::NoState { + return Ok(()); + } + + Pallet::::denote_collected_redemption(&investor, investment_id, status)?; + + Ok(()) + } +} diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index d481424ea3..b6a054e477 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -28,7 +28,7 @@ where Currency: Clone + Copy + PartialEq + Debug, { /// Solely apply state machine to transition one `InvestState` into another - /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#State-diagram. + /// based on the transition, see . /// /// NOTE: MUST call `apply_invest_state_transition` on the post state to /// actually mutate storage. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index a9ebbaa789..f82c14ec26 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -32,7 +32,7 @@ use crate::{ InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason, }, - CollectedRedemptionTrancheTokens, Config, Error, Event, ForeignInvestmentInfo, + CollectedInvestment, CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionPayoutCurrency, RedemptionState, SwapOf, TokenSwapOrderIds, }; @@ -40,49 +40,6 @@ use crate::{ mod invest; mod redeem; -// Hook execution for (partially) fulfilled token swaps which should be consumed -// by `TokenSwaps`. -impl StatusNotificationHook for Pallet { - type Error = DispatchError; - type Id = T::TokenSwapOrderId; - type Status = SwapOf; - - fn notify_status_change( - id: T::TokenSwapOrderId, - status: SwapOf, - ) -> Result<(), DispatchError> { - let info = ForeignInvestmentInfo::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; - let reason = info - .last_swap_reason - .ok_or(Error::::TokenSwapReasonNotFound)?; - - match reason { - TokenSwapReason::Investment => { - let pre_state = InvestmentState::::get(&info.owner, info.id); - let post_state = pre_state - .transition(InvestTransition::FulfillSwapOrder(status)) - .map_err(|e| { - // Inner error holds finer granularity but should never occur - log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(InvestError::FulfillSwapOrder) - })?; - Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) - } - TokenSwapReason::Redemption => { - let pre_state = RedemptionState::::get(&info.owner, info.id); - let post_state = pre_state - .transition(RedeemTransition::FulfillSwapOrder(status)) - .map_err(|e| { - // Inner error holds finer granularity but should never occur - log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(RedeemError::FulfillSwapOrder) - })?; - Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) - } - } - } -} - impl ForeignInvestment for Pallet { type Amount = T::Balance; type CollectInvestResult = ExecutedForeignCollectInvest; @@ -245,35 +202,17 @@ impl ForeignInvestment for Pallet { foreign_payout_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result, DispatchError> { - // No need to transition or update state as collection of tranche tokens is - // independent of the current `InvestState` - let CollectedAmount:: { - amount_collected, - amount_payment, - } = T::Investment::collect_investment(who.clone(), investment_id)?; - - // Update invest state - let pre_state = InvestmentState::::get(who, investment_id); - let investing_amount = T::Investment::investment(who, investment_id)?; - let post_state = - pre_state.transition(InvestTransition::CollectInvestment(investing_amount))?; - Self::apply_invest_state_transition(who, investment_id, post_state).map_err(|e| { - log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Collect) - })?; - - // Determine payout amount in foreign currency instead of current pool currency - // denomination - let amount_currency_payout = T::CurrencyConverter::stable_to_stable( - pool_currency, - amount_payment, + // Note: We assume the configured Investment trait to notify about the collected + // amounts via the `CollectedInvestmentHook` which handles incrementing the + // `CollectedInvestment` amount. + T::Investment::collect_investment(who.clone(), investment_id)?; + + Self::transfer_collected_investment( + who, + investment_id, foreign_payout_currency, - )?; - - Ok(ExecutedForeignCollectInvest { - amount_currency_payout, - amount_tranche_tokens_payout: amount_collected, - }) + pool_currency, + ) } #[transactional] @@ -287,37 +226,24 @@ impl ForeignInvestment for Pallet { RedemptionPayoutCurrency::::get(who, investment_id) .map(|currency| currency == foreign_payout_currency) .unwrap_or_else(|| { - log::debug!("Redemption payout currency missing when calling decrease. Should never occur if redemption has been increased beforehand"); + log::debug!("Corruption: Redemption payout currency missing when calling decrease. Should never occur if redemption has been increased beforehand"); false }), Error::::InvalidRedemptionPayoutCurrency ); - let collected = T::Investment::collect_redemption(who.clone(), investment_id)?; - CollectedRedemptionTrancheTokens::::try_mutate(who, investment_id, |amount| { - amount.ensure_add_assign(collected.amount_payment)?; - - Ok::<(), DispatchError>(()) - })?; - - // Transition state to initiate swap from pool to foreign currency - let pre_state = RedemptionState::::get(who, investment_id); - let amount_unprocessed_redemption = T::Investment::redemption(who, investment_id)?; - let post_state = pre_state - .transition(RedeemTransition::CollectRedemption( - amount_unprocessed_redemption, - SwapOf:: { - amount: collected.amount_collected, - currency_in: foreign_payout_currency, - currency_out: pool_currency, - }, - )) - .map_err(|e| { - // Inner error holds finer granularity but should never occur - log::debug!("RedeemState transition error: {:?}", e); - Error::::from(RedeemError::Collect) - })?; + ensure!(T::PoolInspect::currency_for(investment_id.of_pool()) + .map(|currency| currency == pool_currency) + .unwrap_or_else(|| { + log::debug!("Corruption: Failed to derive pool currency from investment id when collecting foreign redemption. Should never occur if redemption has been increased beforehand"); + false + }), + DispatchError::Corruption + ); - Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; + // Note: We assume the configured Investment trait to notify about the collected + // amounts via the `CollectedRedemptionHook` which handles incrementing the + // `CollectedRedemption` amount. + T::Investment::collect_redemption(who.clone(), investment_id)?; Ok(()) } @@ -668,8 +594,10 @@ impl Pallet { state: RedeemState, inner_redeem_state: InnerRedeemState, ) -> Result>, DispatchError> { - let amount_payment_tranche_tokens = - CollectedRedemptionTrancheTokens::::get(who, investment_id); + let CollectedAmount:: { + amount_payment: amount_payment_tranche_tokens, + .. + } = CollectedRedemption::::get(who, investment_id); // Send notification and kill `CollectedRedemptionTrancheTokens` iff the state // includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` @@ -690,7 +618,7 @@ impl Pallet { amount_payment: amount_payment_tranche_tokens, }, )?; - CollectedRedemptionTrancheTokens::::remove(who, investment_id); + CollectedRedemption::::remove(who, investment_id); Ok(()) } _ => Ok(()), @@ -1059,17 +987,131 @@ impl Pallet { Ok((token_swap, new_invest_state, new_redeem_state)) } - /// Sends `ExecutedDecreaseInvestHook` notification such that any potential - /// consumer could act upon that, e.g. Liquidity Pools for + /// Increments the collected investment amount and transitions investment + /// state as a result of collecting the investment. + /// + /// NOTE: Does not transfer back the collected tranche tokens. This happens + /// in `transfer_collected_investment`. + pub(crate) fn denote_collected_investment( + who: &T::AccountId, + investment_id: T::InvestmentId, + collected: CollectedAmount, + ) -> DispatchResult { + // Increment by previously stored amounts (via `CollectedInvestmentHook`) + CollectedInvestment::::mutate(who, investment_id, |collected_before| { + collected_before + .amount_collected + .ensure_add_assign(collected.amount_collected)?; + collected_before + .amount_payment + .ensure_add_assign(collected.amount_payment)?; + Ok::<(), DispatchError>(()) + })?; + + // Update invest state to decrease the unprocessed investing amount + let investing_amount = T::Investment::investment(who, investment_id)?; + let pre_state = InvestmentState::::get(who, investment_id); + let post_state = + pre_state.transition(InvestTransition::CollectInvestment(investing_amount))?; + Self::apply_invest_state_transition(who, investment_id, post_state).map_err(|e| { + log::debug!("InvestState transition error: {:?}", e); + Error::::from(InvestError::Collect) + })?; + + Ok(()) + } + + /// Consumes the `CollectedInvestment` amounts and returns these. + /// + /// NOTE: Converts the collected pool currency payment amount to foreign + /// currency via the `CurrencyConverter` trait. + pub(crate) fn transfer_collected_investment( + who: &T::AccountId, + investment_id: T::InvestmentId, + foreign_payout_currency: T::CurrencyId, + pool_currency: T::CurrencyId, + ) -> Result, DispatchError> { + let collected = CollectedInvestment::::take(who, investment_id); + ensure!( + collected.amount_payment.is_zero(), + Error::::InvestError(InvestError::NothingCollected) + ); + + // Determine payout amount in foreign currency instead of current pool currency + // denomination + let amount_currency_payout = T::CurrencyConverter::stable_to_stable( + pool_currency, + collected.amount_payment, + foreign_payout_currency, + )?; + + Ok(ExecutedForeignCollectInvest { + amount_currency_payout, + amount_tranche_tokens_payout: collected.amount_collected, + }) + } + + /// Increments the collected redemption amount and transitions redemption + /// state as a result of collecting the redemption. + /// + /// NOTE: Neither initiates a swap from the collected pool currency into + /// foreign currency nor transfers back any currency to the investor. This + /// happens in `transfer_collected_redemption`. + pub(crate) fn denote_collected_redemption( + who: &T::AccountId, + investment_id: T::InvestmentId, + collected: CollectedAmount, + ) -> DispatchResult { + let foreign_payout_currency = + RedemptionPayoutCurrency::::get(who, investment_id).expect("Foreign redemption payout currency is set by initial increment before collecting is possible"); + let pool_currency = T::PoolInspect::currency_for(investment_id.of_pool()) + .expect("Impossible to collect redemption for non existing pool at this point"); + + // Increment by previously stored amounts (via `CollectedInvestmentHook`) + let collected = CollectedRedemption::::mutate(who, investment_id, |collected_before| { + collected_before + .amount_collected + .ensure_add_assign(collected.amount_collected)?; + collected_before + .amount_payment + .ensure_add_assign(collected.amount_payment)?; + Ok::, DispatchError>(collected_before.clone()) + })?; + + // Transition state to initiate swap from pool to foreign currency + let pre_state = RedemptionState::::get(who, investment_id); + let amount_unprocessed_redemption = T::Investment::redemption(who, investment_id)?; + let post_state = pre_state + .transition(RedeemTransition::CollectRedemption( + amount_unprocessed_redemption, + SwapOf:: { + amount: collected.amount_collected, + currency_in: foreign_payout_currency, + currency_out: pool_currency, + }, + )) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("RedeemState transition error: {:?}", e); + Error::::from(RedeemError::Collect) + })?; + + Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; + + Ok(()) + } + + /// Sends `DecreasedForeignInvestOrderHook` notification such that any + /// potential consumer could act upon that, e.g. Liquidity Pools for /// `ExecutedDecreaseInvestOrder`. #[transactional] - fn notify_executed_decrease_invest( + pub(crate) fn notify_executed_decrease_invest( who: &T::AccountId, investment_id: T::InvestmentId, foreign_currency: T::CurrencyId, amount_decreased: T::Balance, ) -> DispatchResult { - T::ExecutedDecreaseInvestHook::notify_status_change( + T::DecreasedForeignInvestOrderHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), id: investment_id, @@ -1083,17 +1125,17 @@ impl Pallet { ) } - /// Sends `ExecutedCollectRedeemHook` notification such that any potential - /// consumer could act upon that, e.g. Liquidity Pools for + /// Sends `CollectedForeignRedemptionHook` notification such that any + /// potential consumer could act upon that, e.g. Liquidity Pools for /// `ExecutedCollectRedeemOrder`. #[transactional] - fn notify_executed_collect_redeem( + pub(crate) fn notify_executed_collect_redeem( who: &T::AccountId, investment_id: T::InvestmentId, currency: T::CurrencyId, collected: CollectedAmount, ) -> DispatchResult { - T::ExecutedCollectRedeemHook::notify_status_change( + T::CollectedForeignRedemptionHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), id: investment_id, diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index c8ae18a18d..ab12209ada 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -42,7 +42,7 @@ where Currency: Clone + Copy + PartialEq + Debug, { /// Solely apply state machine to transition one `RedeemState` into another - /// based on the transition, see https://centrifuge.hackmd.io/IPtRlOrOSrOF9MHjEY48BA?view#Redemption-States + /// based on the transition, see /// /// NOTE: MUST call `apply_redeem_state_transition` on the post state to /// actually mutate storage. diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index a0e2b66801..d60bd72468 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -11,6 +11,36 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +//! # Foreign Investment pallet +//! +//! Enables investing, redeeming and collecting in foreign and non-foreign +//! currencies. Can be regarded as an extension of `pallet-investment` which +//! provides the same toolset for pool (non-foreign) currencies. +//! +//! - [`Pallet`] +//! +//! ## Assumptions +//! +//! - The implementer of the pallet's associated `Investment` type sends +//! notifications for collected investments via `CollectedInvestmentHook` and +//! for collected redemptions via `CollectedRedemptionHook`]. Otherwise the +//! payment and collected amounts for foreign investments/redemptions are +//! never incremented. +//! - The implementer of the pallet's associated `TokenSwaps` type sends +//! notifications for fulfilled swap orders via the `FulfilledSwapOrderHook`. +//! Otherwise investment/redemption states can never advance the +//! `ActiveSwapInto*Currency` state. +//! - The implementer of the pallet's associated `TokenSwaps` type sends +//! notifications for fulfilled swap orders via the `FulfilledSwapOrderHook`. +//! Otherwise investment/redemption states can never advance the +//! `ActiveSwapInto*Currency` state. +//! - The implementer of the pallet's associated +//! `DecreasedForeignInvestOrderHook` type handles the refund of the decreased +//! amount to the investor. +//! - The implementer of the pallet's associated +//! `CollectedForeignRedemptionHook` type handles the transfer of the +//! collected amount in foreign currency to the investor. + #![cfg_attr(not(feature = "std"), no_std)] use cfg_types::investments::Swap; @@ -20,6 +50,7 @@ use cfg_types::investments::Swap; pub use pallet::*; pub mod errors; +pub mod hooks; pub mod impls; pub mod types; @@ -116,7 +147,7 @@ pub mod pallet { Self::AccountId, Error = DispatchError, InvestmentId = Self::InvestmentId, - Result = CollectedAmount, + Result = (), >; /// Type for price ratio for cost of incoming currency relative to @@ -162,7 +193,7 @@ pub mod pallet { >; /// The hook type which acts upon a finalized investment decrement. - type ExecutedDecreaseInvestHook: StatusNotificationHook< + type DecreasedForeignInvestOrderHook: StatusNotificationHook< Id = cfg_types::investments::ForeignInvestmentInfo< Self::AccountId, Self::InvestmentId, @@ -173,7 +204,7 @@ pub mod pallet { >; /// The hook type which acts upon a finalized redemption collection. - type ExecutedCollectRedeemHook: StatusNotificationHook< + type CollectedForeignRedemptionHook: StatusNotificationHook< Id = cfg_types::investments::ForeignInvestmentInfo< Self::AccountId, Self::InvestmentId, @@ -271,21 +302,44 @@ pub mod pallet { T::TokenSwapOrderId, >; - /// Maps an investor and their `InvestmentId` to the amount of - /// tranche tokens burned for the conversion into pool currency based on the - /// fulfillment price(s) during collection. + /// Maps an investor and their `InvestmentId` to the collected investment + /// amount, i.e., the payment amount of pool currency burned for the + /// conversion into collected amount of tranche tokens based on the + /// fulfillment price(s). + /// + /// NOTE: The lifetime of this storage starts with receiving a notification + /// of an executed investment via the `CollectedInvestmentHook`. It ends + /// with transferring the collected tranche tokens by executing + /// `transfer_collected_investment` which is part of + /// `collect_foreign_investment`. + #[pallet::storage] + pub type CollectedInvestment = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::InvestmentId, + CollectedAmount, + ValueQuery, + >; + + /// Maps an investor and their `InvestmentId` to the collected redemption + /// amount, i.e., the payment amount of tranche tokens burned for the + /// conversion into collected pool currency based on the + /// fulfillment price(s). /// - /// NOTE: The lifetime of this storage starts with collecting a redemption - /// in pool currency and ends with having swapped the entire amount to - /// return currency which is assumed to be asynchronous. + /// NOTE: The lifetime of this storage starts with receiving a notification + /// of an executed redemption collection into pool currency via the + /// `CollectedRedemptionHook`. It ends with having swapped the entire amount + /// to foreign currency which is assumed to be asynchronous. #[pallet::storage] - pub type CollectedRedemptionTrancheTokens = StorageDoubleMap< + pub type CollectedRedemption = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Blake2_128Concat, T::InvestmentId, - T::Balance, + CollectedAmount, ValueQuery, >; diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 07b630c792..bdda533dd4 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -19,15 +19,17 @@ use cfg_traits::{ Investment, InvestmentAccountant, InvestmentCollector, InvestmentProperties, InvestmentsPortfolio, OrderManager, }, - PreConditions, + PreConditions, StatusNotificationHook, }; use cfg_types::{ fixed_point::FixedPointNumberExtension, - investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection}, + investments::{ + CollectedAmount, ForeignInvestmentInfo, InvestCollection, InvestmentAccount, + RedeemCollection, + }, orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ - dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, pallet_prelude::*, traits::tokens::fungibles::{Inspect, Mutate, Transfer}, }; @@ -105,6 +107,7 @@ pub enum CollectType { #[frame_support::pallet] pub mod pallet { + use cfg_types::investments::ForeignInvestmentInfo; use sp_runtime::{traits::AtLeast32BitUnsigned, FixedPointNumber, FixedPointOperand}; use super::*; @@ -173,6 +176,24 @@ pub mod pallet { Result = DispatchResult, >; + /// The hook which acts upon a collected investment. + /// + /// NOTE: NOOP if the investment is not foreign. + type CollectedInvestmentHook: StatusNotificationHook< + Error = DispatchError, + Id = ForeignInvestmentInfo, + Status = CollectedAmount, + >; + + /// The hook which acts upon a (partially) fulfilled order + /// + /// NOTE: NOOP if the redemption is not foreign. + type CollectedRedemptionHook: StatusNotificationHook< + Error = DispatchError, + Id = ForeignInvestmentInfo, + Status = CollectedAmount, + >; + /// The weight information for this pallet extrinsics. type WeightInfo: weights::WeightInfo; } @@ -441,7 +462,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_collect_invest(who, investment_id).map(|(_, info)| info) + Self::do_collect_invest(who, investment_id) } /// Collect the results of a user's redeem orders for the given @@ -455,7 +476,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - Self::do_collect_redeem(who, investment_id).map(|(_, info)| info) + Self::do_collect_redeem(who, investment_id) } /// Collect the results of another users invest orders for the given @@ -470,7 +491,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_collect_invest(who, investment_id).map(|(_, info)| info) + Self::do_collect_invest(who, investment_id) } /// Collect the results of another users redeem orders for the given @@ -485,7 +506,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_collect_redeem(who, investment_id).map(|(_, info)| info) + Self::do_collect_redeem(who, investment_id) } } } @@ -634,7 +655,7 @@ where pub(crate) fn do_collect_invest( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> DispatchResultWithPostInfo { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; InvestOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -647,7 +668,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + Storage::read() + Storage::write() - return Ok((Default::default(), ().into())); + return Ok(().into()); }; let mut collection = InvestCollection::::from_order(order); @@ -668,7 +689,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok((Default::default(), ().into())); + return Ok(().into()); } let mut amount_payment = T::Amount::zero(); @@ -730,8 +751,18 @@ where }, }); + // NOOP if investment is not foreign + T::CollectedInvestmentHook::notify_status_change( + ForeignInvestmentInfo { + owner: who.clone(), + id: investment_id, + last_swap_reason: None, + }, + collected_investment, + )?; + // TODO: Actually weight with amount of collects here - Ok((collected_investment, ().into())) + Ok(().into()) }) } @@ -739,7 +770,7 @@ where pub(crate) fn do_collect_redeem( who: T::AccountId, investment_id: T::InvestmentId, - ) -> Result<(CollectedAmount, PostDispatchInfo), DispatchErrorWithPostInfo> { + ) -> DispatchResultWithPostInfo { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; RedeemOrders::::try_mutate(&who, investment_id, |maybe_order| { // Exit early if order does not exist @@ -753,7 +784,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + Storage::read() + Storage::write() - return Ok((Default::default(), ().into())); + return Ok(().into()); }; let mut collection = RedeemCollection::::from_order(order); @@ -774,7 +805,7 @@ where }); // TODO: Return correct weight // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok((Default::default(), ().into())); + return Ok(().into()); } let mut amount_payment = T::Amount::zero(); @@ -843,8 +874,18 @@ where }, }); + // NOOP if investment is not foreign + T::CollectedRedemptionHook::notify_status_change( + ForeignInvestmentInfo { + owner: who.clone(), + id: investment_id, + last_swap_reason: None, + }, + collected_redemption, + )?; + // TODO: Actually weight this with collected_ids - Ok((collected_redemption, ().into())) + Ok(().into()) }) } @@ -1461,25 +1502,17 @@ where { type Error = DispatchError; type InvestmentId = T::InvestmentId; - type Result = CollectedAmount; + type Result = (); - // TODO: Write unit test in investments to test this - fn collect_investment( - who: T::AccountId, - investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + fn collect_investment(who: T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { Pallet::::do_collect_invest(who, investment_id) .map_err(|e| e.error) - .map(|(collected_amount, _)| collected_amount) + .map(|_| ()) } - // TODO: Write unit test in investments to test this - fn collect_redemption( - who: T::AccountId, - investment_id: T::InvestmentId, - ) -> Result, DispatchError> { + fn collect_redemption(who: T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { Pallet::::do_collect_redeem(who, investment_id) .map_err(|e| e.error) - .map(|(collected_amount, _)| collected_amount) + .map(|_| ()) } } diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index 567b327b3d..f70b7e2f61 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -140,6 +140,17 @@ cfg_test_utils::mocks::accountant::impl_mock_accountant!( Balance ); +pub struct NoopCollectHook; +impl cfg_traits::StatusNotificationHook for NoopCollectHook { + type Error = sp_runtime::DispatchError; + type Id = cfg_types::investments::ForeignInvestmentInfo; + type Status = cfg_types::investments::CollectedAmount; + + fn notify_status_change(_id: Self::Id, _status: Self::Status) -> DispatchResult { + Ok(()) + } +} + parameter_types! { pub const MaxOutstandingCollect: u64 = 10; } @@ -148,6 +159,8 @@ impl pallet_investments::Config for MockRuntime { type Accountant = MockAccountant; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = NoopCollectHook; + type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = InvestmentId; type MaxOutstandingCollects = MaxOutstandingCollect; type PreConditions = Always; diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index 5907223b8d..4754a608db 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -26,13 +26,13 @@ use sp_std::marker::PhantomData; use crate::{pallet::Config, Message, MessageOf, Pallet}; /// The hook struct which acts upon a finalized investment decrement. -pub struct DecreaseInvestOrderHook(PhantomData); +pub struct DecreasedForeignInvestOrderHook(PhantomData); /// The hook struct which acts upon a finalized redemption collection. -pub struct CollectRedeemHook(PhantomData); +pub struct CollectedForeignRedemptionHook(PhantomData); -impl StatusNotificationHook for DecreaseInvestOrderHook +impl StatusNotificationHook for DecreasedForeignInvestOrderHook where ::AccountId: Into<[u8; 32]>, { @@ -69,7 +69,7 @@ where } } -impl StatusNotificationHook for CollectRedeemHook +impl StatusNotificationHook for CollectedForeignRedemptionHook where ::AccountId: Into<[u8; 32]>, { diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index d83e7c34e5..694fbb52ce 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -127,9 +127,9 @@ where /// back into the provided foreign currency initiated. /// /// The finalization of this call (fulfillment of the swap) is assumed to be - /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` - /// which burns the corresponding amount in foreign currency and dispatches - /// `ExecutedDecreaseInvestOrder`. + /// asynchronous. In any case, it is handled by + /// `DecreasedForeignInvestOrderHook` which burns the corresponding amount + /// in foreign currency and dispatches `ExecutedDecreaseInvestOrder`. pub fn handle_decrease_invest_order( pool_id: T::PoolId, tranche_id: T::TrancheId, @@ -159,9 +159,9 @@ where /// On success, initiates a swap back into the provided foreign currency. /// /// The finalization of this call (fulfillment of the swap) is assumed to be - /// asynchronous. In any case, it is handled by `DecreaseInvestOrderHook` - /// which burns the corresponding amount in foreign currency and dispatches - /// `ExecutedDecreaseInvestOrder`. + /// asynchronous. In any case, it is handled by + /// `DecreasedForeignInvestOrderHook` which burns the corresponding amount + /// in foreign currency and dispatches `ExecutedDecreaseInvestOrder`. pub fn handle_cancel_invest_order( pool_id: T::PoolId, tranche_id: T::TrancheId, @@ -353,9 +353,9 @@ where /// collected amount in pool currency into the desired foreign currency. /// /// The termination of this call (fulfillment of the swap) is assumed to be - /// asynchronous and handled by the `CollectRedeemHook`. It burns the return - /// currency amount and dispatches `Message::ExecutedCollectRedeem` to the - /// destination domain. + /// asynchronous and handled by the `CollectedForeignRedemptionHook`. It + /// burns the return currency amount and dispatches + /// `Message::ExecutedCollectRedeem` to the destination domain. pub fn handle_collect_redemption( pool_id: T::PoolId, tranche_id: T::TrancheId, diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index a946aa6b2e..fcb55c46a4 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -10,6 +10,34 @@ // 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. + +//! # Liquidity Pools pallet +//! +//! Provides the toolset to enable foreign investments on foreign domains. +//! +//! - [`Pallet`] +//! +//! ## Assumptions +//! - Sending/recipient domains handle cross-chain transferred currencies +//! properly on their side. This pallet only ensures correctness on the local +//! domain. +//! - The implementer of the pallet's associated `ForeignInvestment` type sends +//! notifications for completed investment decrements via the +//! `DecreasedForeignInvestOrderHook`. Otherwise the domain which initially +//! sent the `DecreaseInvestOrder` message will never be notified about the +//! completion. +//! - The implementer of the pallet's associated `ForeignInvestment` type sends +//! notifications for completed redemption collections via the +//! `CollectedForeignRedemptionHook`. Otherwise the domain which initially +//! sent the `CollectRedeem` message will never be notified about the +//! completion. +//! - The pallet's associated `TreasuryAccount` holds sufficient balance for the +//! corresponding fee currencies of all possible recipient domains for the +//! following outgoing messages: [`Message::ExecutedDecreaseInvestOrder`], +//! [`Message::ExecutedDecreaseRedeemOrder`], +//! [`Message::ExecutedCollectInvest`], [`Message::ExecutedCollectRedeem`], +//! [`Message::ScheduleUpgrade`]. + #![cfg_attr(not(feature = "std"), no_std)] use core::convert::TryFrom; @@ -715,53 +743,6 @@ pub mod pallet { Message::ScheduleUpgrade { contract }, ) } - - // TODO: Split up, see https://centrifuge.hackmd.io/tKGS5CwqSQeeI3bU1dKUlw#Action-items - /// Collect a user's foreign investment as if we had received a - /// `CollectInvest` message from another domain. - #[pallet::call_index(11)] - #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] - pub fn collect_foreign_investment_for( - origin: OriginFor, - pool_id: T::PoolId, - tranche_id: T::TrancheId, - investor: T::AccountId, - ) -> DispatchResult { - ensure_signed(origin)?; - - Self::handle_collect_investment( - pool_id, - tranche_id, - investor, - todo!("query via foreign investments"), - todo!("derive via currency"), - )?; - - Ok(()) - } - - // TODO: Split up, see https://centrifuge.hackmd.io/tKGS5CwqSQeeI3bU1dKUlw#Action-items - /// Collect a user's foreign redemption as if we had received a - /// `CollectRedeem` message from another domain. - #[pallet::call_index(12)] - #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] - pub fn collect_foreign_redemption_for( - origin: OriginFor, - pool_id: T::PoolId, - tranche_id: T::TrancheId, - investor: T::AccountId, - ) -> DispatchResult { - ensure_signed(origin)?; - - Self::handle_collect_redemption( - pool_id, - tranche_id, - investor, - todo!("query via foreign investments"), - )?; - - Ok(()) - } } impl Pallet { diff --git a/pallets/pool-registry/src/mock.rs b/pallets/pool-registry/src/mock.rs index 0faa015e1f..81f409664a 100644 --- a/pallets/pool-registry/src/mock.rs +++ b/pallets/pool-registry/src/mock.rs @@ -303,6 +303,16 @@ impl orml_tokens::Config for Test { type WeightInfo = (); } +pub struct NoopCollectHook; +impl cfg_traits::StatusNotificationHook for NoopCollectHook { + type Error = DispatchError; + type Id = cfg_types::investments::ForeignInvestmentInfo; + type Status = cfg_types::investments::CollectedAmount; + + fn notify_status_change(_id: Self::Id, _status: Self::Status) -> DispatchResult { + Ok(()) + } +} parameter_types! { pub const MaxOutstandingCollects: u32 = 10; } @@ -310,6 +320,8 @@ impl pallet_investments::Config for Test { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = NoopCollectHook; + type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = Always; diff --git a/pallets/pool-system/src/mock.rs b/pallets/pool-system/src/mock.rs index dcdf60201e..6a13a50fc3 100644 --- a/pallets/pool-system/src/mock.rs +++ b/pallets/pool-system/src/mock.rs @@ -250,6 +250,16 @@ where } } +pub struct NoopCollectHook; +impl cfg_traits::StatusNotificationHook for NoopCollectHook { + type Error = sp_runtime::DispatchError; + type Id = cfg_types::investments::ForeignInvestmentInfo; + type Status = cfg_types::investments::CollectedAmount; + + fn notify_status_change(_id: Self::Id, _status: Self::Status) -> DispatchResult { + Ok(()) + } +} parameter_types! { pub const MaxOutstandingCollects: u32 = 10; } @@ -257,6 +267,8 @@ impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = NoopCollectHook; + type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = Always; diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 0701f22d6c..47cd39a64d 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -62,6 +62,7 @@ use pallet_anchors::AnchorData; pub use pallet_balances::Call as BalancesCall; use pallet_collective::{EnsureMember, EnsureProportionMoreThan}; use pallet_evm::{Account as EVMAccount, FeeCalculator, Runner}; +use pallet_foreign_investments::hooks::FulfilledSwapOrderHook; use pallet_investments::OrderType; use pallet_pool_system::{ pool_types::{PoolDetails, ScheduledUpdateDetails}, @@ -1392,13 +1393,14 @@ parameter_types! { impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; + type CollectedForeignRedemptionHook = + pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; + type DecreasedForeignInvestOrderHook = + pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; type DefaultTokenSellRate = DefaultTokenSellRate; - type ExecutedCollectRedeemHook = pallet_liquidity_pools::hooks::CollectRedeemHook; - type ExecutedDecreaseInvestHook = - pallet_liquidity_pools::hooks::DecreaseInvestOrderHook; type Investment = Investments; type InvestmentId = TrancheCurrency; type PoolId = PoolId; @@ -1682,6 +1684,10 @@ impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = + pallet_foreign_investments::hooks::CollectedInvestmentHook; + type CollectedRedemptionHook = + pallet_foreign_investments::hooks::CollectedRedemptionHook; type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = IsTrancheInvestor; @@ -1791,7 +1797,7 @@ impl pallet_order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; - type FulfilledOrderHook = ForeignInvestments; + type FulfilledOrderHook = FulfilledSwapOrderHook; type MinimumOrderAmount = MinimumOrderAmount; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; diff --git a/runtime/centrifuge/Cargo.toml b/runtime/centrifuge/Cargo.toml index 1cd0f4f868..28745858bd 100644 --- a/runtime/centrifuge/Cargo.toml +++ b/runtime/centrifuge/Cargo.toml @@ -113,6 +113,7 @@ pallet-crowdloan-claim = { path = "../../pallets/crowdloan-claim", default-featu pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-features = false } pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } +# pallet-foreign-investments = { path = "../../pallets/foreign-investments", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-keystore = { path = "../../pallets/keystore", default-features = false } @@ -187,6 +188,7 @@ std = [ "pallet-evm-precompile-dispatch/std", "pallet-evm-chain-id/std", "pallet-fees/std", + # "pallet-foreign-investments/std", "pallet-identity/std", "pallet-interest-accrual/std", "pallet-investments/std", @@ -268,6 +270,7 @@ runtime-benchmarks = [ "pallet-ethereum/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", + # "pallet-foreign-investments/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", @@ -340,6 +343,7 @@ try-runtime = [ "pallet-evm/try-runtime", "pallet-evm-chain-id/try-runtime", "pallet-fees/try-runtime", + # "pallet-foreign-investments/try-runtime", "pallet-identity/try-runtime", "pallet-interest-accrual/try-runtime", "pallet-investments/try-runtime", diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 9682890c8a..68eb4262df 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -22,7 +22,7 @@ pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as _}, - Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, StatusNotificationHook, }; use cfg_types::{ consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes}, @@ -1548,10 +1548,24 @@ impl< } } +// TODO: Remove when adding pallet_foreign_investments to runtime +pub struct NoopCollectHook; +impl StatusNotificationHook for NoopCollectHook { + type Error = DispatchError; + type Id = cfg_types::investments::ForeignInvestmentInfo; + type Status = cfg_types::investments::CollectedAmount; + + fn notify_status_change(_id: Self::Id, _status: Self::Status) -> DispatchResult { + Ok(()) + } +} + impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = NoopCollectHook; + type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = IsTrancheInvestor; diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 6817658646..88ef886e4e 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1580,13 +1580,14 @@ parameter_types! { impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; + type CollectedForeignRedemptionHook = + pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter; type CurrencyId = CurrencyId; + type DecreasedForeignInvestOrderHook = + pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; type DefaultTokenSellRate = DefaultTokenSellRate; - type ExecutedCollectRedeemHook = pallet_liquidity_pools::hooks::CollectRedeemHook; - type ExecutedDecreaseInvestHook = - pallet_liquidity_pools::hooks::DecreaseInvestOrderHook; type Investment = Investments; type InvestmentId = TrancheCurrency; type PoolId = PoolId; @@ -1699,6 +1700,10 @@ impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Rate; + type CollectedInvestmentHook = + pallet_foreign_investments::hooks::CollectedInvestmentHook; + type CollectedRedemptionHook = + pallet_foreign_investments::hooks::CollectedRedemptionHook; type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = IsTrancheInvestor; @@ -1900,7 +1905,7 @@ impl pallet_order_book::Config for Runtime { type AssetCurrencyId = CurrencyId; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; - type FulfilledOrderHook = ForeignInvestments; + type FulfilledOrderHook = pallet_foreign_investments::hooks::FulfilledSwapOrderHook; type MinimumOrderAmount = MinimumOrderAmount; type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 8066f81877..46d6011dd6 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -712,10 +712,9 @@ fn inbound_collect_redeem_order() { })); // Foreign CollectedRedemptionTrancheTokens should be killed - assert!(!pallet_foreign_investments::CollectedRedemptionTrancheTokens::::contains_key( - investor.clone(), - default_investment_id(), - )); + assert!(!pallet_foreign_investments::CollectedRedemption::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id(),)); // Foreign RedemptionState should be killed assert!(!pallet_foreign_investments::RedemptionState::< From 89841d42f6b6e12192f64c2ed11b39c4866d38bc Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 25 Aug 2023 18:38:25 +0200 Subject: [PATCH 60/96] feat: implicitly collect on swap fulfillment --- pallets/foreign-investments/src/hooks.rs | 34 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 949e3ac21b..49bb85d501 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -11,10 +11,11 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::StatusNotificationHook; -use cfg_types::investments::{ - CollectedAmount, ForeignInvestmentInfo, +use cfg_traits::{ + investments::{Investment, InvestmentCollector}, + StatusNotificationHook, }; +use cfg_types::investments::{CollectedAmount, ForeignInvestmentInfo}; use frame_support::transactional; use sp_runtime::{DispatchError, DispatchResult}; use sp_std::marker::PhantomData; @@ -53,6 +54,19 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { match reason { TokenSwapReason::Investment => { + // If the investment requires to be collected, the transition of the + // `InvestState` would fail. By implicitly collecting here, we defend against + // that and ensure that the swap order fulfillment won't be reverted (since this + // function is `transactional`). + + // NOTE: We only collect the tranche tokens, but do not transfer them back. This + // updates the unprocessed investment amount such that transitioning the + // `InvestState` is not blocked. The user still has to do that manually by + // sending `CollectInvest`. + if T::Investment::investment_requires_collect(&info.owner, info.id) { + T::Investment::collect_investment(info.owner.clone(), info.id)?; + } + let pre_state = InvestmentState::::get(&info.owner, info.id); let post_state = pre_state .transition(InvestTransition::FulfillSwapOrder(status)) @@ -64,6 +78,20 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) } TokenSwapReason::Redemption => { + // If the investment requires to be collected, the transition of the + // `RedeemState` would fail. By implicitly collecting here, we defend against + // that and ensure that the swap order fulfillment won't be reverted (since this + // function is `transactional`). + + // NOTE: We only collect the pool currency, but do neither transfer them to the + // investor nor initiate the swap back into foreign currency. This updates the + // unprocessed investment amount such that transitioning the `RedeemState` is + // not blocked. The user still has to do that manually by + // sending `CollectInvest`. + if T::Investment::redemption_requires_collect(&info.owner, info.id) { + T::Investment::collect_redemption(info.owner.clone(), info.id)?; + } + let pre_state = RedemptionState::::get(&info.owner, info.id); let post_state = pre_state .transition(RedeemTransition::FulfillSwapOrder(status)) From 033e2d95d71c1822540e111d4f1fd36e64298a86 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Sat, 26 Aug 2023 08:07:52 +0200 Subject: [PATCH 61/96] fix: collect --- pallets/foreign-investments/src/impls/mod.rs | 2 +- pallets/investments/src/lib.rs | 406 ++++++++++-------- .../non_foreign_investments.rs | 5 + 3 files changed, 221 insertions(+), 192 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index f82c14ec26..30a704af20 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -1033,7 +1033,7 @@ impl Pallet { ) -> Result, DispatchError> { let collected = CollectedInvestment::::take(who, investment_id); ensure!( - collected.amount_payment.is_zero(), + !collected.amount_payment.is_zero(), Error::::InvestError(InvestError::NothingCollected) ); diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index bdda533dd4..35e82c328f 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -30,6 +30,7 @@ use cfg_types::{ orders::{FulfillmentWithPrice, Order, TotalOrder}, }; use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, pallet_prelude::*, traits::tokens::fungibles::{Inspect, Mutate, Transfer}, }; @@ -657,101 +658,113 @@ where investment_id: T::InvestmentId, ) -> DispatchResultWithPostInfo { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; - InvestOrders::::try_mutate(&who, investment_id, |maybe_order| { - // Exit early if order does not exist - let order = if let Some(order) = maybe_order.as_mut() { - order - } else { - Self::deposit_event(Event::::InvestCollectedWithoutActivePosition { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + Storage::read() + Storage::write() - return Ok(().into()); - }; - - let mut collection = InvestCollection::::from_order(order); - let mut collected_ids = Vec::new(); - let cur_order_id = InvestOrderId::::get(investment_id); - let last_processed_order_id = min( - order - .submitted_at() - .saturating_add(T::MaxOutstandingCollects::get()), - cur_order_id, - ); - - // Exit early if the current order is not in processing - if order.submitted_at() == cur_order_id { - Self::deposit_event(Event::::InvestCollectedForNonClearedOrderId { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok(().into()); - } - - let mut amount_payment = T::Amount::zero(); - for order_id in order.submitted_at()..last_processed_order_id { - let fulfillment = ClearedInvestOrders::::try_get(investment_id, order_id) - .map_err(|_| Error::::OrderNotCleared)?; - - let currency_payout = - Pallet::::acc_payout_invest(&mut collection, &fulfillment)?; - Pallet::::acc_remaining_invest(&mut collection, &fulfillment)?; - collected_ids.push(order_id); - - amount_payment.ensure_add_assign( - fulfillment - .price - .checked_mul_int_floor(currency_payout) - .ok_or(ArithmeticError::Overflow)?, + let (collected_investment, post_dispatch_info) = InvestOrders::::try_mutate( + &who, + investment_id, + |maybe_order| -> Result< + (CollectedAmount, PostDispatchInfo), + DispatchErrorWithPostInfo, + > { + // Exit early if order does not exist + let order = if let Some(order) = maybe_order.as_mut() { + order + } else { + Self::deposit_event(Event::::InvestCollectedWithoutActivePosition { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + }; + + let mut collection = InvestCollection::::from_order(order); + let mut collected_ids = Vec::new(); + let cur_order_id = InvestOrderId::::get(investment_id); + let last_processed_order_id = min( + order + .submitted_at() + .saturating_add(T::MaxOutstandingCollects::get()), + cur_order_id, + ); + + // Exit early if the current order is not in processing + if order.submitted_at() == cur_order_id { + Self::deposit_event(Event::::InvestCollectedForNonClearedOrderId { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + 2 * Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + } + + let mut amount_payment = T::Amount::zero(); + for order_id in order.submitted_at()..last_processed_order_id { + let fulfillment = ClearedInvestOrders::::try_get(investment_id, order_id) + .map_err(|_| Error::::OrderNotCleared)?; + + let currency_payout = + Pallet::::acc_payout_invest(&mut collection, &fulfillment)?; + Pallet::::acc_remaining_invest(&mut collection, &fulfillment)?; + collected_ids.push(order_id); + + amount_payment.ensure_add_assign( + fulfillment + .price + .checked_mul_int_floor(currency_payout) + .ok_or(ArithmeticError::Overflow)?, + )?; + } + + order.update_after_collect( + collection.remaining_investment_invest, + last_processed_order_id, + ); + + T::Accountant::transfer( + info.id(), + &InvestmentAccount { investment_id }.into_account_truncating(), + &who, + collection.payout_investment_invest, )?; - } - order.update_after_collect( - collection.remaining_investment_invest, - last_processed_order_id, - ); + let amount = order.amount(); + Self::rm_empty( + amount, + maybe_order, + Event::InvestOrderUpdated { + investment_id, + submitted_at: last_processed_order_id, + who: who.clone(), + amount, + }, + ); - T::Accountant::transfer( - info.id(), - &InvestmentAccount { investment_id }.into_account_truncating(), - &who, - collection.payout_investment_invest, - )?; + let collected_investment = CollectedAmount { + amount_collected: collection.payout_investment_invest, + amount_payment, + }; - let amount = order.amount(); - Self::rm_empty( - amount, - maybe_order, - Event::InvestOrderUpdated { + Self::deposit_event(Event::InvestOrdersCollected { investment_id, - submitted_at: last_processed_order_id, who: who.clone(), - amount, - }, - ); - - let collected_investment = CollectedAmount { - amount_collected: collection.payout_investment_invest, - amount_payment, - }; - - Self::deposit_event(Event::InvestOrdersCollected { - investment_id, - who: who.clone(), - processed_orders: collected_ids, - collection, - outcome: if last_processed_order_id == cur_order_id { - CollectOutcome::FullyCollected - } else { - CollectOutcome::PartiallyCollected - }, - }); + processed_orders: collected_ids, + collection, + outcome: if last_processed_order_id == cur_order_id { + CollectOutcome::FullyCollected + } else { + CollectOutcome::PartiallyCollected + }, + }); - // NOOP if investment is not foreign + // TODO: Actually weight with amount of collects here + Ok((collected_investment, ().into())) + }, + )?; + + if collected_investment != Default::default() { + // Assumption: NOOP if investment is not foreign T::CollectedInvestmentHook::notify_status_change( ForeignInvestmentInfo { owner: who.clone(), @@ -760,10 +773,9 @@ where }, collected_investment, )?; + } - // TODO: Actually weight with amount of collects here - Ok(().into()) - }) + Ok(post_dispatch_info) } #[allow(clippy::type_complexity)] @@ -772,109 +784,122 @@ where investment_id: T::InvestmentId, ) -> DispatchResultWithPostInfo { let info = T::Accountant::info(investment_id).map_err(|_| Error::::UnknownInvestment)?; - RedeemOrders::::try_mutate(&who, investment_id, |maybe_order| { - // Exit early if order does not exist - let order = if let Some(order) = maybe_order.as_mut() { - order - } else { - // Trigger event - Self::deposit_event(Event::::RedeemCollectedWithoutActivePosition { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + Storage::read() + Storage::write() - return Ok(().into()); - }; - - let mut collection = RedeemCollection::::from_order(order); - let mut collected_ids = Vec::new(); - let cur_order_id = RedeemOrderId::::get(investment_id); - let last_processed_order_id = min( - order - .submitted_at() - .saturating_add(T::MaxOutstandingCollects::get()), - cur_order_id, - ); - - // Exit early if the current order is not in processing - if order.submitted_at() == cur_order_id { - Self::deposit_event(Event::::RedeemCollectedForNonClearedOrderId { - who: who.clone(), - investment_id, - }); - // TODO: Return correct weight - // - Accountant::info() + 2 * Storage::read() + Storage::write() - return Ok(().into()); - } - - let mut amount_payment = T::Amount::zero(); - for order_id in order.submitted_at()..last_processed_order_id { - let fulfillment = ClearedRedeemOrders::::try_get(investment_id, order_id) - .map_err(|_| Error::::OrderNotCleared)?; - let payout_tranche_tokens = - Pallet::::acc_payout_redeem(&mut collection, &fulfillment)?; - Pallet::::acc_remaining_redeem(&mut collection, &fulfillment)?; - collected_ids.push(order_id); - - // TODO(@mustermeiszer): We actually want the reciprocal without rounding, is - // this sufficient or should we use something like - // `reciprocal_with_rounding(SignedRounding::NearestPrefMajor)` - amount_payment.ensure_add_assign( - fulfillment - .price - .reciprocal_floor() - .ok_or(Error::::ZeroPricedInvestment)? - .checked_mul_int_floor(payout_tranche_tokens) - .ok_or(ArithmeticError::Overflow)?, + let (collected_redemption, post_dispatch_info) = RedeemOrders::::try_mutate( + &who, + investment_id, + |maybe_order| -> Result< + (CollectedAmount, PostDispatchInfo), + DispatchErrorWithPostInfo, + > { + // Exit early if order does not exist + let order = if let Some(order) = maybe_order.as_mut() { + order + } else { + // Trigger event + Self::deposit_event(Event::::RedeemCollectedWithoutActivePosition { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + }; + + let mut collection = RedeemCollection::::from_order(order); + let mut collected_ids = Vec::new(); + let cur_order_id = RedeemOrderId::::get(investment_id); + let last_processed_order_id = min( + order + .submitted_at() + .saturating_add(T::MaxOutstandingCollects::get()), + cur_order_id, + ); + + // Exit early if the current order is not in processing + if order.submitted_at() == cur_order_id { + Self::deposit_event(Event::::RedeemCollectedForNonClearedOrderId { + who: who.clone(), + investment_id, + }); + // TODO: Return correct weight + // - Accountant::info() + 2 * Storage::read() + Storage::write() + return Ok((Default::default(), ().into())); + } + + let mut amount_payment = T::Amount::zero(); + for order_id in order.submitted_at()..last_processed_order_id { + let fulfillment = ClearedRedeemOrders::::try_get(investment_id, order_id) + .map_err(|_| Error::::OrderNotCleared)?; + let payout_tranche_tokens = + Pallet::::acc_payout_redeem(&mut collection, &fulfillment)?; + Pallet::::acc_remaining_redeem(&mut collection, &fulfillment)?; + collected_ids.push(order_id); + + // TODO(@mustermeiszer): We actually want the reciprocal without rounding, is + // this sufficient or should we use something like + // `reciprocal_with_rounding(SignedRounding::NearestPrefMajor)` + amount_payment.ensure_add_assign( + fulfillment + .price + .reciprocal_floor() + .ok_or(Error::::ZeroPricedInvestment)? + .checked_mul_int_floor(payout_tranche_tokens) + .ok_or(ArithmeticError::Overflow)?, + )?; + } + + order.update_after_collect( + collection.remaining_investment_redeem, + last_processed_order_id, + ); + + // Transfer collected amounts from investment and redemption + let investment_account = + InvestmentAccount { investment_id }.into_account_truncating(); + T::Tokens::transfer( + info.payment_currency(), + &investment_account, + &who, + collection.payout_investment_redeem, + false, )?; - } - order.update_after_collect( - collection.remaining_investment_redeem, - last_processed_order_id, - ); - - // Transfer collected amounts from investment and redemption - let investment_account = InvestmentAccount { investment_id }.into_account_truncating(); - T::Tokens::transfer( - info.payment_currency(), - &investment_account, - &who, - collection.payout_investment_redeem, - false, - )?; + let amount = order.amount(); + Self::rm_empty( + amount, + maybe_order, + Event::RedeemOrderUpdated { + investment_id, + submitted_at: last_processed_order_id, + who: who.clone(), + amount, + }, + ); + + let collected_redemption = CollectedAmount { + amount_collected: collection.payout_investment_redeem, + amount_payment, + }; - let amount = order.amount(); - Self::rm_empty( - amount, - maybe_order, - Event::RedeemOrderUpdated { + Self::deposit_event(Event::RedeemOrdersCollected { investment_id, - submitted_at: last_processed_order_id, who: who.clone(), - amount, - }, - ); - - let collected_redemption = CollectedAmount { - amount_collected: collection.payout_investment_redeem, - amount_payment, - }; - - Self::deposit_event(Event::RedeemOrdersCollected { - investment_id, - who: who.clone(), - processed_orders: collected_ids, - collection, - outcome: if last_processed_order_id == cur_order_id { - CollectOutcome::FullyCollected - } else { - CollectOutcome::PartiallyCollected - }, - }); + processed_orders: collected_ids, + collection, + outcome: if last_processed_order_id == cur_order_id { + CollectOutcome::FullyCollected + } else { + CollectOutcome::PartiallyCollected + }, + }); - // NOOP if investment is not foreign + // TODO: Actually weight this with collected_ids + Ok((collected_redemption, ().into())) + }, + )?; + + if collected_redemption != Default::default() { + // Assumption: NOOP if investment is not foreign T::CollectedRedemptionHook::notify_status_change( ForeignInvestmentInfo { owner: who.clone(), @@ -883,10 +908,9 @@ where }, collected_redemption, )?; + } - // TODO: Actually weight this with collected_ids - Ok(().into()) - }) + Ok(post_dispatch_info) } pub(crate) fn do_update_invest_order( diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 46d6011dd6..28c2b6fb40 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -371,6 +371,11 @@ fn inbound_collect_invest_order() { .into() })); + // Foreign CollectedInvestment should be killed + assert!(!pallet_foreign_investments::CollectedInvestment::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + // Foreign InvestmentState should be killed assert!(!pallet_foreign_investments::InvestmentState::< DevelopmentRuntime, From a4edd1611d505e36001a2f20169293ccffd8bbfb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Sat, 26 Aug 2023 08:24:46 +0200 Subject: [PATCH 62/96] fix: order-book benchmarks --- pallets/foreign-investments/src/hooks.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 49bb85d501..5a7992ed42 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -46,8 +46,13 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { id: T::TokenSwapOrderId, status: SwapOf, ) -> Result<(), DispatchError> { - let info = - ForeignInvestmentInfoStorage::::get(id).ok_or(Error::::InvestmentInfoNotFound)?; + let maybe_info = ForeignInvestmentInfoStorage::::get(id); + + if maybe_info.is_none() { + return Ok(()); + } + let info = maybe_info.expect("Cannot be None"); + let reason = info .last_swap_reason .ok_or(Error::::TokenSwapReasonNotFound)?; From 1cbf2151c7ad651122608200f3727a8ca61da841 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 09:12:47 +0200 Subject: [PATCH 63/96] wip: improvements, fixes --- libs/traits/src/lib.rs | 18 +++--- libs/types/src/investments.rs | 7 ++- pallets/liquidity-pools/src/hooks.rs | 8 +-- pallets/order-book/src/lib.rs | 55 ++++++++++++++--- pallets/order-book/src/tests.rs | 9 --- runtime/altair/src/lib.rs | 8 ++- runtime/common/src/lib.rs | 57 +++++++++++------ runtime/development/src/lib.rs | 14 +++-- .../non_foreign_investments.rs | 61 ++++++++++++++----- .../tests/liquidity_pools/setup.rs | 2 +- .../pallet/development/tests/mod.rs | 35 ++++++++++- runtime/integration-tests/src/utils/mod.rs | 8 ++- 12 files changed, 196 insertions(+), 86 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 10e3810b5d..74c2077290 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -508,8 +508,8 @@ pub trait TokenSwaps { /// FOREIGN_ASSET_1_DECIMALS } fn place_order( account: Account, - currency_out: Self::CurrencyId, currency_in: Self::CurrencyId, + currency_out: Self::CurrencyId, buy_amount: Self::Balance, sell_rate_limit: Self::SellRatio, min_fulfillment_amount: Self::Balance, @@ -562,14 +562,10 @@ pub trait TokenSwaps { fn is_active(order: Self::OrderId) -> bool; /// Check whether there already exist orders for the given trading pair. + /// + /// NOTE: By checking existence for (currency_out, currency_in), we know + /// that counter orders exist against which could be traded. fn order_pair_exists(currency_in: Self::CurrencyId, currency_out: Self::CurrencyId) -> bool; - - /// Check whether there already exist counter orders for the given trading - /// pair against which could be traded. - fn counter_order_pair_exists( - currency_in: Self::CurrencyId, - currency_out: Self::CurrencyId, - ) -> bool; } /// Trait to transmit a change of status for anything uniquely identifiable. @@ -590,15 +586,17 @@ pub trait StatusNotificationHook { /// Trait to synchronously provide a currency conversion estimation for foreign /// currencies into/from pool currencies. pub trait SimpleCurrencyConversion { - type Currency; type Balance; + type Currency; type Error; /// Estimate the worth of an outgoing currency amount in the incoming /// currency. + /// + /// NOTE: At least applies decimal conversion if both currencies mismatch. fn stable_to_stable( + currency_in: Self::Currency, currency_out: Self::Currency, amount_out: Self::Balance, - currency_in: Self::Currency, ) -> Result; } diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index c9ffb4cac6..3e3148b653 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -194,10 +194,11 @@ impl(PhantomData); -/// The hook struct which acts upon a finalized redemption collection. - -pub struct CollectedForeignRedemptionHook(PhantomData); - impl StatusNotificationHook for DecreasedForeignInvestOrderHook where ::AccountId: Into<[u8; 32]>, @@ -69,6 +65,10 @@ where } } +/// The hook struct which acts upon a finalized redemption collection. + +pub struct CollectedForeignRedemptionHook(PhantomData); + impl StatusNotificationHook for CollectedForeignRedemptionHook where ::AccountId: Into<[u8; 32]>, diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index adca65a2a8..1a03bb1ea4 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -471,6 +471,11 @@ pub mod pallet { currency_out: T::AssetCurrencyId, buy_amount: T::Balance, ) -> DispatchResult { + #[cfg(feature = "std")] + { + dbg!(T::MinimumOrderAmount::get(&(currency_in, currency_out))); + dbg!(buy_amount); + } match T::MinimumOrderAmount::get(&(currency_in, currency_out)) { Some(amount) if amount <= buy_amount => Ok(()), None => Err(Error::::InvalidTradingPair)?, @@ -491,6 +496,14 @@ pub mod pallet { let to_decimals = T::AssetRegistry::metadata(¤cy_to) .ok_or(Error::::InvalidAssetId)? .decimals; + + #[cfg(feature = "std")] + { + dbg!(from_decimals); + dbg!(to_decimals); + } + // FIXME: Maybe. This equals 10^(to - from) * to_amount when it should be + // multiplied with from_amount? Or convert_balance_decimals(from_decimals, to_decimals, ratio.ensure_mul_int(amount)?) .map_err(DispatchError::from) } @@ -548,8 +561,28 @@ pub mod pallet { let max_sell_amount = Self::convert_with_ratio(currency_in, currency_out, sell_rate_limit, buy_amount)?; + #[cfg(feature = "std")] + { + dbg!(T::TradeableAsset::balance(currency_out, &account)); + dbg!(T::TradeableAsset::balance(currency_in, &account)); + dbg!(&buy_amount, &max_sell_amount, sell_rate_limit); + } + + #[cfg(feature = "std")] + { + dbg!( + "before holding", + T::TradeableAsset::balance(currency_out, &account) > max_sell_amount + ); + } + T::TradeableAsset::hold(currency_out, &account, max_sell_amount)?; + #[cfg(feature = "std")] + { + println!("after holding",); + } + let order_id = >::get(); let new_order = Order { order_id, @@ -569,6 +602,16 @@ pub mod pallet { .map_err(|_| Error::::AssetPairOrdersOverflow) })?; + #[cfg(feature = "std")] + { + dbg!( + "create order", + currency_in, + currency_out, + AssetPairOrders::::get(currency_in, currency_out) + ); + } + >::insert(order_id, new_order.clone()); >::insert(&account, order_id, new_order); Self::deposit_event(Event::OrderCreated { @@ -712,15 +755,7 @@ pub mod pallet { .is_zero() } - /// Check whether there already exist counter orders for the given - /// trading pair against which could be traded. - fn counter_order_pair_exists( - currency_in: Self::CurrencyId, - currency_out: Self::CurrencyId, - ) -> bool { - !AssetPairOrders::::get(currency_out, currency_in) - .len() - .is_zero() - } + // TODO: Either expose conversion here or move to runtime_common + // fn } } diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index 0e6ddfb707..a2d97e7dcb 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -885,16 +885,7 @@ fn order_pair_exists() { 5 * CURRENCY_AUSD_DECIMALS )); assert!(OrderBook::order_pair_exists(currency_in, currency_out)); - assert!(OrderBook::counter_order_pair_exists( - currency_out, - currency_in - )); - assert!(!OrderBook::order_pair_exists(currency_out, currency_in)); - assert!(!OrderBook::counter_order_pair_exists( - currency_in, - currency_out - )); }) } diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 47cd39a64d..a772104a7c 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1388,15 +1388,17 @@ impl pallet_xcm_transactor::Config for Runtime { parameter_types! { pub DefaultTokenSellRate: Rate = Rate::one(); - pub ConversionRate: Rate = Rate::one(); + pub StableToStableRate: Rate = Rate::one(); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CollectedForeignRedemptionHook = pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; - type CurrencyConverter = - runtime_common::foreign_investments::SimpleStableCurrencyConverter; + type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< + OrmlAssetRegistry, + StableToStableRate, + >; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 84d40d0b3f..ed9568a198 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -485,14 +485,15 @@ pub mod xcm_transactor { } pub mod foreign_investments { - use cfg_primitives::Balance; + use cfg_primitives::{conversion::convert_balance_decimals, Balance}; use cfg_traits::SimpleCurrencyConversion; - use cfg_types::{ - fixed_point::{FixedPointNumberExtension, Rate}, - tokens::CurrencyId, - }; + use cfg_types::{fixed_point::Rate, tokens::CurrencyId}; use frame_support::pallet_prelude::PhantomData; - use sp_runtime::{traits::Get, DispatchError}; + use orml_traits::asset_registry::Inspect; + use sp_runtime::{ + traits::{EnsureFixedPointNumber, Get}, + DispatchError, + }; /// Simple stable coin amount converter from one stable to another. Provides /// a synchronous estimation of the amount of one stable currency in @@ -504,32 +505,48 @@ pub mod foreign_investments { /// NOTE: Should be deprecated ASAP! // TODO(@review): Can we determine whether a ForeignAsset is a stable coin at // this point of time? - pub struct SimpleStableCurrencyConverter(PhantomData); + pub struct SimpleStableCurrencyConverter( + PhantomData<(AssetRegistry, StableToStableRate)>, + ); - impl SimpleCurrencyConversion - for SimpleStableCurrencyConverter + impl SimpleCurrencyConversion + for SimpleStableCurrencyConverter where - RateForeignToPool: Get, + AssetRegistry: Inspect< + AssetId = CurrencyId, + Balance = Balance, + CustomMetadata = cfg_types::tokens::CustomMetadata, + >, + StableToStableRate: Get, { type Balance = Balance; type Currency = CurrencyId; type Error = DispatchError; fn stable_to_stable( + currency_in: Self::Currency, currency_out: Self::Currency, amount_out: Self::Balance, - currency_in: Self::Currency, ) -> Result { match (currency_out, currency_in) { - (out, inc) if out == inc => Ok(amount_out), - // TODO(future): Conversion must be limited to asset ids which reflect stable coins - (CurrencyId::ForeignAsset(_out_id), CurrencyId::ForeignAsset(_in_id)) => { - // NOTE: Rounding down to favor system side - RateForeignToPool::get() - .checked_mul_int_floor(amount_out) - .ok_or(DispatchError::Arithmetic( - sp_arithmetic::ArithmeticError::Overflow, - )) + (from, to) if from == to => Ok(amount_out), + (CurrencyId::ForeignAsset(_), CurrencyId::ForeignAsset(_)) => { + let from_metadata = AssetRegistry::metadata(¤cy_out) + .ok_or(DispatchError::CannotLookup)?; + let to_metadata = + AssetRegistry::metadata(¤cy_in).ok_or(DispatchError::CannotLookup)?; + frame_support::ensure!( + from_metadata.additional.pool_currency + || to_metadata.additional.pool_currency, + DispatchError::Token(sp_runtime::TokenError::Unsupported) + ); + + convert_balance_decimals( + from_metadata.decimals, + to_metadata.decimals, + StableToStableRate::get().ensure_mul_int(amount_out)?, + ) + .map_err(|e| DispatchError::from(e)) } _ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)), } diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 88ef886e4e..1c534e87b4 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1575,15 +1575,17 @@ impl orml_asset_registry::Config for Runtime { parameter_types! { pub DefaultTokenSellRate: Rate = Rate::one(); - pub ConversionRate: Rate = Rate::one(); + pub StableToStableRate: Rate = Rate::one(); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CollectedForeignRedemptionHook = pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; - type CurrencyConverter = - runtime_common::foreign_investments::SimpleStableCurrencyConverter; + type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< + OrmlAssetRegistry, + StableToStableRate, + >; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; @@ -1879,7 +1881,7 @@ parameter_types! { // This will be replaced by runtime specifiable minimum, // which will likely be set by governance. const DEV_USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); -const DEV_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); +const DEV_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(3); const DEV_USDT_DECIMALS: u128 = 1_000_000; const DEV_AUSD_DECIMALS: u128 = 1_000_000_000_000; const DEFAULT_DEV_MIN_ORDER: u128 = 5; @@ -1889,6 +1891,10 @@ const MIN_DEV_NATIVE_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * CFG; parameter_type_with_key! { pub MinimumOrderAmount: |pair: (CurrencyId, CurrencyId)| -> Option { + #[cfg(feature = "std")]{ + dbg!(&pair); + dbg!(MIN_DEV_AUSD_ORDER); + } match pair { (CurrencyId::Native, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), (DEV_AUSD_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_AUSD_ORDER), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs index 28c2b6fb40..74c6f244bd 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs @@ -951,8 +951,15 @@ mod should_fail { } mod mismatching_currencies { + use cfg_traits::SimpleCurrencyConversion; + use development_runtime::{DefaultTokenSellRate, OrderBook, StableToStableRate}; + use runtime_common::foreign_investments::SimpleStableCurrencyConverter; + use super::*; - use crate::utils::GLMR_CURRENCY_ID; + use crate::{ + liquidity_pools::pallet::development::tests::register_usdt, + utils::{GLMR_CURRENCY_ID, USDT_CURRENCY_ID}, + }; #[test] fn invest_increase_another_currency() { @@ -960,49 +967,71 @@ mod should_fail { Development::execute_with(|| { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; - let invest_amount: u128 = 100_000_000; let investor: AccountId = BOB.into(); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = GLMR_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_currency: u128 = 5_000_000_000_000; create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); do_initial_increase_investment( pool_id, - invest_amount, + invest_amount_pool_currency, investor.clone(), pool_currency, ); - enable_liquidity_pool_transferability(pool_currency); - // Should fail to increase in another currency + // USDT investment preparations + register_usdt(); + let invest_amount_foreign_currency: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_currency, + ) + .unwrap(); + assert_ok!(OrmlTokens::mint_into( + pool_currency, + &ALICE.into(), + invest_amount_pool_currency + )); + + // Should fail to increase to an invalid payment currency let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { pool_id, tranche_id: default_tranche_id(pool_id), investor: investor.clone().into(), currency: general_currency_index(foreign_currency), - amount: 1, + amount: invest_amount_foreign_currency, }; assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg.clone()), pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); - // TODO: Add foreign currency to accepted payment - - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::Increase - ) - ); + // Create counter order (pool to foreign) such that foreign_currency is accepted + // as payment + assert_ok!(OrderBook::create_order( + RuntimeOrigin::signed(ALICE.into()), + foreign_currency, + pool_currency, + invest_amount_foreign_currency, + DefaultTokenSellRate::get() + )); + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + ),); // Should fail to decrease in another currency + enable_liquidity_pool_transferability(foreign_currency); let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { pool_id, tranche_id: default_tranche_id(pool_id), investor: investor.clone().into(), currency: general_currency_index(foreign_currency), - amount: 1, + amount: invest_amount_foreign_currency, }; assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs index b5abba27c3..123f248c60 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -322,7 +322,7 @@ pub(crate) mod investments { use cfg_primitives::AccountId; use cfg_traits::investments::TrancheCurrency as TrancheCurrencyT; use cfg_types::investments::InvestmentAccount; - use development_runtime::PoolSystem; + use development_runtime::{OrderBook, PoolSystem}; use pallet_pool_system::tranches::TrancheLoc; use super::*; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs index 7acc7e185a..5e3d34ba68 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs @@ -6,17 +6,18 @@ use orml_traits::asset_registry::AssetMetadata; use runtime_common::xcm::general_key; use xcm::{ latest::MultiLocation, - prelude::{Parachain, X2}, + prelude::{GeneralIndex, PalletInstance, Parachain, X2, X3}, VersionedMultiLocation, }; -use crate::utils::AUSD_CURRENCY_ID; +use crate::utils::{AUSD_CURRENCY_ID, USDT_CURRENCY_ID}; mod liquidity_pools; mod routers; /// Register AUSD in the asset registry. -/// It should be executed within an externalities environment. +/// +/// NOTE: Assumes to be executed within an externalities environment. fn register_ausd() { let meta: AssetMetadata = AssetMetadata { decimals: 12, @@ -43,3 +44,31 @@ fn register_ausd() { Some(AUSD_CURRENCY_ID) )); } + +/// Register USDT in the asset registry and enable LiquidityPools cross chain +/// transferability. +/// +/// NOTE: Assumes to be executed within an externalities environment. +fn register_usdt() { + let meta: AssetMetadata = AssetMetadata { + decimals: 6, + name: "Tether USDT".into(), + symbol: "USDT".into(), + existential_deposit: 10_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X3(Parachain(1000), PalletInstance(50), GeneralIndex(1984)), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::LiquidityPools, + pool_currency: true, + ..CustomMetadata::default() + }, + }; + + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + meta, + Some(USDT_CURRENCY_ID) + )); +} diff --git a/runtime/integration-tests/src/utils/mod.rs b/runtime/integration-tests/src/utils/mod.rs index 1d3ea32f94..686713f73b 100644 --- a/runtime/integration-tests/src/utils/mod.rs +++ b/runtime/integration-tests/src/utils/mod.rs @@ -28,10 +28,12 @@ pub mod time; pub mod tokens; /// The relay native token's asset id -pub const RELAY_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(1); +pub const RELAY_ASSET_ID: CurrencyId = CurrencyId::ForeignAsset(5); /// The Glimmer asset id -pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1000); +pub const GLMR_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(4); /// The AUSD asset id -pub const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2000); +pub const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(3); +/// The USDT asset id +pub const USDT_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); /// The EVM Chain id of Moonbeam pub const MOONBEAM_EVM_CHAIN_ID: u64 = 1284; From 4abe81c89821abcdb00694740c06da2c37f42d25 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 09:13:58 +0200 Subject: [PATCH 64/96] wip: apply correct amount conversion to InvestState --- .../foreign-investments/src/impls/invest.rs | 77 +++++++++++++------ pallets/foreign-investments/src/impls/mod.rs | 47 +++++------ pallets/foreign-investments/src/lib.rs | 4 +- pallets/foreign-investments/src/types.rs | 68 +++++++++------- 4 files changed, 123 insertions(+), 73 deletions(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index b6a054e477..deb9160dd5 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -13,19 +13,20 @@ use core::cmp::Ordering; +use cfg_traits::SimpleCurrencyConversion; use cfg_types::investments::Swap; -use frame_support::dispatch::fmt::Debug; use sp_runtime::{ - traits::{EnsureAdd, EnsureSub}, + traits::{EnsureAdd, EnsureSub, Zero}, ArithmeticError, DispatchError, }; use crate::types::{InvestState, InvestTransition}; -impl InvestState -where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - Currency: Clone + Copy + PartialEq + Debug, +impl InvestState +// impl InvestState +// where +// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, +// Currency: Clone + Copy + PartialEq + Debug, { /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see . @@ -34,8 +35,12 @@ where /// actually mutate storage. pub fn transition( &self, - transition: InvestTransition, + transition: InvestTransition, ) -> Result { + #[cfg(feature = "std")] + { + dbg!(&transition); + } match transition { InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(self, swap), InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(self, swap), @@ -53,7 +58,7 @@ where /// * If the state includes `ActiveSwapInto{Pool, Return}Currency`, it /// returns `Some(swap)`. /// * Else, it returns `None`. - pub(crate) fn get_active_swap(&self) -> Option> { + pub(crate) fn get_active_swap(&self) -> Option> { match *self { InvestState::NoState => None, InvestState::InvestmentOngoing { .. } => None, @@ -75,7 +80,7 @@ where } /// Returns the `invest_amount` if existent, else zero. - pub(crate) fn get_investing_amount(&self) -> Balance { + pub(crate) fn get_investing_amount(&self) -> T::Balance { match *self { InvestState::InvestmentOngoing { invest_amount} | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { invest_amount, .. } | @@ -83,16 +88,17 @@ where InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | InvestState::SwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, - _ => Balance::zero() + _ => T::Balance::zero() } } } // Actual impl of transition -impl InvestState -where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - Currency: Clone + Copy + PartialEq + Debug, +impl InvestState +// impl InvestState +// where +// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, +// Currency: Clone + Copy + PartialEq + Debug, { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// invest state diagram: @@ -137,10 +143,19 @@ where /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! - fn handle_increase(&self, swap: Swap) -> Result { + fn handle_increase( + &self, + swap: Swap, + ) -> Result { if swap.currency_in == swap.currency_out { return Self::handle_increase_non_foreign(self, swap); } + #[cfg(feature = "std")] + { + println!("inside handle increase"); + // dbg!(&self); + dbg!(&swap); + } match &self { Self::NoState => Ok(Self::ActiveSwapIntoPoolCurrency { swap }), @@ -394,11 +409,22 @@ where /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! - fn handle_decrease(&self, swap: Swap) -> Result { + // FIXME: Currency conversion off + fn handle_decrease( + &self, + swap: Swap, + ) -> Result { if swap.currency_in == swap.currency_out { return Self::handle_decrease_non_foreign(self, swap); } + #[cfg(feature = "std")] + { + println!("handle_decrease"); + // dbg!(&self); + dbg!(&swap); + } + match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency InvestState::NoState @@ -411,7 +437,10 @@ where match swap.amount.cmp(invest_amount) { Ordering::Less => { Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap, + swap: Swap { + amount: T::CurrencyConverter::stable_to_stable(swap.currency_in, swap.currency_out, swap.amount)?, + ..swap + }, invest_amount: *invest_amount - swap.amount, }) }, @@ -458,6 +487,10 @@ where let invest_amount = invest_amount.ensure_sub(done_amount)?; let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; + #[cfg(feature = "std")]{ + dbg!(&swap.amount, pool_swap.amount, &max_decrease_amount); + } + if swap.amount < pool_swap.amount { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { @@ -596,7 +629,7 @@ where // the `CurrencyConverter` is decoupled from the `TokenSwaps` trait. fn handle_fulfilled_swap_order( &self, - swap: Swap, + swap: Swap, ) -> Result { match &self { InvestState::NoState | InvestState::InvestmentOngoing { .. } => Err(DispatchError::Other( @@ -805,7 +838,7 @@ where /// this can never occur! fn handle_increase_non_foreign( &self, - swap: Swap, + swap: Swap, ) -> Result { match &self { Self::NoState => Ok(Self::InvestmentOngoing { @@ -846,7 +879,7 @@ where /// this can never occur! fn handle_decrease_non_foreign( &self, - swap: Swap, + swap: Swap, ) -> Result { if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { @@ -872,8 +905,8 @@ where /// invested amount. /// * Else the unprocessed amount should be zero. If it is not, state is /// corrupted as this reflects the investment was increased improperly. - fn handle_collect(&self, unprocessed_amount: Balance) -> Result { - match *self { + fn handle_collect(&self, unprocessed_amount: T::Balance) -> Result { + match self.clone() { Self::InvestmentOngoing { .. } => { if unprocessed_amount.is_zero() { Ok(Self::NoState) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 30a704af20..d9b3bb5a79 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -55,6 +55,9 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + // Translate amount from foreign to pool_currency + let amount = + T::CurrencyConverter::stable_to_stable(pool_currency, foreign_currency, amount)?; // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( @@ -74,7 +77,6 @@ impl ForeignInvestment for Pallet { Error::::from(InvestError::Increase) })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; - Ok(()) } @@ -86,6 +88,9 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { + // Translate amount from foreign to pool_currency + let amount = + T::CurrencyConverter::stable_to_stable(pool_currency, foreign_currency, amount)?; // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( @@ -101,14 +106,14 @@ impl ForeignInvestment for Pallet { let post_state = pre_state .transition(InvestTransition::DecreaseInvestOrder(Swap { - currency_in: pool_currency, - currency_out: foreign_currency, + currency_in: foreign_currency, + currency_out: pool_currency, amount, })) .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Decrease) + Error::::from(InvestError::Increase) })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; @@ -267,10 +272,7 @@ impl ForeignInvestment for Pallet { true } else { T::PoolInspect::currency_for(investment_id.of_pool()) - .map(|pool_currency| { - // TODO(@review): Or just `order_pair_exists`? - T::TokenSwaps::counter_order_pair_exists(currency, pool_currency) - }) + .map(|pool_currency| T::TokenSwaps::order_pair_exists(currency, pool_currency)) .unwrap_or(false) } } @@ -325,7 +327,7 @@ impl Pallet { pub(crate) fn apply_invest_state_transition( who: &T::AccountId, investment_id: T::InvestmentId, - state: InvestState, + state: InvestState, ) -> DispatchResult { // Must not send executed decrease notification before updating redemption let mut maybe_executed_decrease: Option<(T::CurrencyId, T::Balance)> = None; @@ -338,7 +340,7 @@ impl Pallet { Ok((InvestState::NoState, None, Zero::zero())) }, InvestState::InvestmentOngoing { invest_amount } => { - InvestmentState::::insert(who, investment_id, state); + InvestmentState::::insert(who, investment_id, state.clone()); Ok((state, None, invest_amount)) }, @@ -346,21 +348,21 @@ impl Pallet { InvestState::ActiveSwapIntoForeignCurrency { swap } | // We don't care about `done_amount` until swap into foreign is fulfilled InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { - InvestmentState::::insert(who, investment_id, state); + InvestmentState::::insert(who, investment_id, state.clone()); Ok((state, Some(swap), Zero::zero())) }, InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount } | InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, invest_amount } | // We don't care about `done_amount` until swap into foreign is fulfilled InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap,invest_amount, .. } => { - InvestmentState::::insert(who, investment_id, state); + InvestmentState::::insert(who, investment_id, state.clone()); Ok((state, Some(swap), invest_amount)) }, InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, done_amount } => { maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrency { swap }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); Ok((new_state, Some(swap), Zero::zero())) }, @@ -368,7 +370,7 @@ impl Pallet { maybe_executed_decrease = Some((swap.currency_out, done_amount)); let new_state = InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); Ok((new_state, Some(swap), invest_amount)) }, @@ -383,14 +385,13 @@ impl Pallet { maybe_executed_decrease = Some((done_swap.currency_in, done_swap.amount)); let new_state = InvestState::InvestmentOngoing { invest_amount }; - InvestmentState::::insert(who, investment_id, new_state); + InvestmentState::::insert(who, investment_id, new_state.clone()); Ok((new_state, None, invest_amount)) }, } .map(|(invest_state, maybe_swap, invest_amount)| { let (maybe_invest_state_prio, maybe_new_redeem_state) = Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; - // Dispatch transition event, post swap state has priority if it exists as it was the last transition if let Some(invest_state_prio) = maybe_invest_state_prio { Self::deposit_investment_event(who, investment_id, Some(invest_state_prio)); @@ -528,7 +529,7 @@ impl Pallet { fn deposit_investment_event( who: &T::AccountId, investment_id: T::InvestmentId, - maybe_state: Option>, + maybe_state: Option>, ) { match maybe_state { Some(state) if state == InvestState::NoState => { @@ -680,7 +681,7 @@ impl Pallet { reason: TokenSwapReason, ) -> Result< ( - Option>, + Option>, Option>, ), DispatchError, @@ -703,8 +704,8 @@ impl Pallet { // Update invest and redeem states if necessary InvestmentState::::mutate(who, investment_id, |current_invest_state| { // Should never occur but let's be safe - if let Some(state) = maybe_invest_state { - *current_invest_state = state; + if let Some(state) = &maybe_invest_state { + *current_invest_state = state.clone(); } }); @@ -800,8 +801,8 @@ impl Pallet { _ => { let swap_order_id = T::TokenSwaps::place_order( who.clone(), - swap.currency_out, swap.currency_in, + swap.currency_out, swap.amount, // The max accepted sell rate is independent of the asset type for now T::DefaultTokenSellRate::get(), @@ -858,7 +859,7 @@ impl Pallet { ) -> Result< ( Option>, - Option>, + Option>, Option>, ), DispatchError, @@ -1040,9 +1041,9 @@ impl Pallet { // Determine payout amount in foreign currency instead of current pool currency // denomination let amount_currency_payout = T::CurrencyConverter::stable_to_stable( + foreign_payout_currency, pool_currency, collected.amount_payment, - foreign_payout_currency, )?; Ok(ExecutedForeignCollectInvest { diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index d60bd72468..54b9493b04 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -246,7 +246,7 @@ pub mod pallet { T::AccountId, Blake2_128Concat, T::InvestmentId, - InvestState, + InvestState, ValueQuery, >; @@ -363,7 +363,7 @@ pub mod pallet { ForeignInvestmentUpdated { investor: T::AccountId, investment_id: T::InvestmentId, - state: InvestState, + state: InvestState, }, ForeignInvestmentCleared { investor: T::AccountId, diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index b45d685da4..eb92e4038b 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -13,7 +13,7 @@ use cfg_types::investments::Swap; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::dispatch::fmt::Debug; +use frame_support::{dispatch::fmt::Debug, RuntimeDebugNoBound}; use scale_info::TypeInfo; use sp_runtime::traits::{EnsureAdd, EnsureSub}; @@ -33,48 +33,54 @@ pub enum TokenSwapReason { /// fully processed. #[derive( Clone, - Default, PartialOrd, Ord, Copy, PartialEq, Eq, - Debug, + RuntimeDebugNoBound, Encode, Decode, TypeInfo, MaxEncodedLen, )] +// #[cfg_attr(feature = "std", derive(Debug))] +#[scale_info(skip_type_params(T))] +// #[codec(mel_bound())] pub enum InvestState< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - Currency: Clone + Copy + PartialEq + Debug, + // Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + // Currency: Clone + Copy + PartialEq + Debug, + T: crate::Config, > { - #[default] /// Placeholder state for initialization which will never be stored on /// chain. NoState, /// The investment is waiting to be processed. - InvestmentOngoing { invest_amount: Balance }, + InvestmentOngoing { invest_amount: T::Balance }, /// The investment is currently swapped into the required pool currency. - ActiveSwapIntoPoolCurrency { swap: Swap }, + ActiveSwapIntoPoolCurrency { + swap: Swap, + }, /// The unprocessed investment was fully decreased and is currently swapped /// back into the corresponding foreign currency. - ActiveSwapIntoForeignCurrency { swap: Swap }, + ActiveSwapIntoForeignCurrency { + swap: Swap, + }, /// The investment is not fully swapped into pool currency and thus split /// into two parts: /// * One part is still being swapped. /// * The remainder is already waiting to be processed as investment. ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap, - invest_amount: Balance, + swap: Swap, + invest_amount: T::Balance, }, /// The investment is split into two parts: /// * One part is waiting to be processed as investment. /// * The remainder is swapped back into the foreign currency as a result of /// decreasing the invested amount before being processed. ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap: Swap, - invest_amount: Balance, + swap: Swap, + invest_amount: T::Balance, }, /// The investment is split into two parts: /// * The one part is swapping into pool currency. @@ -85,14 +91,14 @@ pub enum InvestState< /// by applying the corresponding trigger to handle the foreign return /// amount. ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { - swap: Swap, - done_amount: Balance, + swap: Swap, + done_amount: T::Balance, }, /// The investment is swapped back into the foreign currency and was already /// partially fulfilled. ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap, - done_amount: Balance, + swap: Swap, + done_amount: T::Balance, }, /// The investment is split into three parts: /// * One part is currently swapping into the pool currency. @@ -104,9 +110,9 @@ pub enum InvestState< /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` by applying the /// corresponding trigger to handle the foreign return amount. ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap: Swap, - done_amount: Balance, - invest_amount: Balance, + swap: Swap, + done_amount: T::Balance, + invest_amount: T::Balance, }, /// The investment is split into three parts: /// * One is waiting to be processed as investment. @@ -117,15 +123,17 @@ pub enum InvestState< /// NOTE: This state should not be transitioned by applying the trigger for /// the done part but wait until the active swap is fulfilled. ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap: Swap, - done_amount: Balance, - invest_amount: Balance, + swap: Swap, + done_amount: T::Balance, + invest_amount: T::Balance, }, /// The unprocessed investment was swapped back into foreign currency. /// /// NOTE: This state can be killed by applying the corresponding trigger to /// handle the foreign return amount. - SwapIntoForeignDone { done_swap: Swap }, + SwapIntoForeignDone { + done_swap: Swap, + }, /// The investment is split into two parts: /// * One part is waiting to be processed as an investment /// * The swapped back into the foreign currency as a result of decreasing @@ -134,11 +142,17 @@ pub enum InvestState< /// NOTE: This state can be transitioned into `InvestmentOngoing` by /// applying the corresponding trigger to handle the foreign return amount. SwapIntoForeignDoneAndInvestmentOngoing { - done_swap: Swap, - invest_amount: Balance, + done_swap: Swap, + invest_amount: T::Balance, }, } +impl Default for InvestState { + fn default() -> Self { + Self::NoState + } +} + /// Reflects all state transitions of an `InvestmentState` which can be /// externally triggered, i.e. by (partially) fulfilling a token swap order or /// updating an unprocessed investment. @@ -328,3 +342,5 @@ pub enum RedeemTransition< FulfillSwapOrder(Swap), CollectRedemption(Balance, Swap), } + +// impl InvestState {} From 4b136a98df9be8330ff36646a852560b4aa933b2 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 17:47:02 +0200 Subject: [PATCH 65/96] fix: invest token denominations mismatching currencies --- pallets/foreign-investments/src/hooks.rs | 2 +- .../foreign-investments/src/impls/invest.rs | 453 +++--- pallets/foreign-investments/src/impls/mod.rs | 26 +- pallets/foreign-investments/src/types.rs | 131 +- pallets/order-book/src/lib.rs | 40 - runtime/development/src/lib.rs | 4 - .../liquidity_pools/foreign_investments.rs | 1342 +++++++++++++++++ .../development/tests/liquidity_pools/mod.rs | 1 - .../non_foreign_investments.rs | 1250 --------------- 9 files changed, 1716 insertions(+), 1533 deletions(-) delete mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 5a7992ed42..4909ffe603 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -136,7 +136,7 @@ impl StatusNotificationHook for CollectedInvestmentHook { let pre_state = InvestmentState::::get(&investor, investment_id); // Exit early if there is no foreign investment - if pre_state == InvestState::NoState { + if pre_state == InvestState::::NoState { return Ok(()); } diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index deb9160dd5..f4234923fb 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -20,13 +20,15 @@ use sp_runtime::{ ArithmeticError, DispatchError, }; -use crate::types::{InvestState, InvestTransition}; +use crate::types::{InvestState, InvestStateConfig, InvestTransition}; -impl InvestState -// impl InvestState -// where -// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, -// Currency: Clone + Copy + PartialEq + Debug, +impl InvestState +where + T: InvestStateConfig, + /* impl InvestState + * where + * Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + * Currency: Clone + Copy + PartialEq + Debug, */ { /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see . @@ -37,10 +39,6 @@ impl InvestState &self, transition: InvestTransition, ) -> Result { - #[cfg(feature = "std")] - { - dbg!(&transition); - } match transition { InvestTransition::IncreaseInvestOrder(swap) => Self::handle_increase(self, swap), InvestTransition::DecreaseInvestOrder(swap) => Self::handle_decrease(self, swap), @@ -94,11 +92,13 @@ impl InvestState } // Actual impl of transition -impl InvestState -// impl InvestState -// where -// Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, -// Currency: Clone + Copy + PartialEq + Debug, +impl InvestState +where + T: InvestStateConfig, + /* impl InvestState + * where + * Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, + * Currency: Clone + Copy + PartialEq + Debug, */ { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// invest state diagram: @@ -137,12 +137,16 @@ impl InvestState /// by 500. The resulting state is /// `(done_amount = 1500, pool_swap.amount = 100, investing = 500)`. /// - /// NOTE: We can ignore handling all states which include - /// `*SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency*` as we - /// consume the done amount and transition in the post transition phase. - /// To be safe and to not make any unhandled assumptions, we throw - /// `DispatchError::Other` for these states though we need to make sure - /// this can never occur! + /// NOTES: + /// * We can never directly compare `swap.amount` and `invest_amount` with + /// `foreign_swap.amount` and `done_amount` if the currencies mismatch as + /// the former pair is denominated in pool currency and the latter one in + /// foreign currency. + /// * We can ignore handling all states which include `*SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency*` as we consume the done amount + /// and transition in the post transition phase. To be safe and to not + /// make any unhandled assumptions, we throw `DispatchError::Other` for + /// these states though we need to make sure this can never occur! fn handle_increase( &self, swap: Swap, @@ -150,12 +154,6 @@ impl InvestState if swap.currency_in == swap.currency_out { return Self::handle_increase_non_foreign(self, swap); } - #[cfg(feature = "std")] - { - println!("inside handle increase"); - // dbg!(&self); - dbg!(&swap); - } match &self { Self::NoState => Ok(Self::ActiveSwapIntoPoolCurrency { swap }), @@ -180,40 +178,47 @@ impl InvestState // well adding foreign_done amount by the minimum of active swap amounts Self::ActiveSwapIntoForeignCurrency { swap: foreign_swap } => { swap.ensure_currencies_match(foreign_swap, false)?; - let invest_amount = swap.amount.min(foreign_swap.amount); - let done_amount = swap.amount.min(foreign_swap.amount); + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_in, + swap.currency_out, + foreign_swap.amount, + )?; + let pool_amount_foreign_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; - match swap.amount.cmp(&foreign_swap.amount) { - // pool swap amount is immediately invested and done amount increased equally - Ordering::Equal => { - Ok( - Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap: Swap { - // safe since swap.amount < foreign_swap.amount - amount: foreign_swap.amount - swap.amount, - ..*foreign_swap - }, - done_amount, - invest_amount, + match swap.amount.cmp(&foreign_amount_pool_denominated) { + // Pool swap amount is immediately fulfilled, i.e. invested and marked as done into foreign + Ordering::Less => { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: Swap { + amount: foreign_swap + .amount + .ensure_sub(pool_amount_foreign_denominated)?, + ..*foreign_swap }, - ) + done_amount: pool_amount_foreign_denominated, + invest_amount: swap.amount, + }) } - // swap amount is immediately invested and done amount increased equally - Ordering::Less => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + // Both opposite swaps are immediately fulfilled, i.e. invested and marked as done + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: *foreign_swap, - invest_amount, + invest_amount: swap.amount, }), - // foreign swap amount is immediately invested and done amount increased equally + // Foreign swap amount is immediately fulfilled, i.e. invested and marked as done Ordering::Greater => { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > foreign_swap.amount - amount: swap.amount - foreign_swap.amount, + // safe since amount_in_foreign > foreign_swap.amount + amount: swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..swap }, - done_amount, - invest_amount, + done_amount: foreign_swap.amount, + invest_amount: swap.amount, }, ) } @@ -241,18 +246,29 @@ impl InvestState invest_amount, } => { swap.ensure_currencies_match(foreign_swap, false)?; + + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_in, + swap.currency_out, + foreign_swap.amount, + )?; + let pool_amount_foreign_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; let invest_amount = - invest_amount.ensure_add(swap.amount.min(foreign_swap.amount))?; - let done_amount = swap.amount.min(foreign_swap.amount); + invest_amount.ensure_add(swap.amount.min(foreign_amount_pool_denominated))?; + let done_amount = pool_amount_foreign_denominated.min(foreign_swap.amount); - match swap.amount.cmp(&foreign_swap.amount) { - // pool swap amount is immediately invested and done amount increased equally - Ordering::Equal => { + match swap.amount.cmp(&foreign_amount_pool_denominated) { + // Pool swap amount is immediately fulfilled, i.e. invested and marked as done + // into foreign + Ordering::Less => { Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < foreign_swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(pool_amount_foreign_denominated)?, ..*foreign_swap }, done_amount, @@ -260,18 +276,17 @@ impl InvestState }, ) } - // swap amount is immediately invested and done amount increased equally - Ordering::Less => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + // Both opposite swaps are immediately fulfilled, i.e. invested and marked as done + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: *foreign_swap, invest_amount, }), - // foreign swap amount is immediately invested and done amount increased equally + // Foreign swap amount is immediately fulfilled, i.e. invested and marked as done Ordering::Greater => { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > foreign_swap.amount - amount: swap.amount - foreign_swap.amount, + amount: swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..swap }, done_amount, @@ -288,25 +303,30 @@ impl InvestState done_amount, } => { swap.ensure_currencies_match(foreign_swap, false)?; - let invest_amount = swap.amount.min(foreign_swap.amount); - let done_amount = invest_amount.ensure_add(*done_amount)?; - // pool swap amount is immediately invested and done amount increased equally - match swap.amount.cmp(&foreign_swap.amount) { - Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { - done_swap: Swap { - amount: done_amount, - ..*foreign_swap - }, - invest_amount, - }), - // swap amount is immediately invested and done amount increased equally + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_in, + swap.currency_out, + foreign_swap.amount, + )?; + let pool_amount_foreign_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; + let invest_amount = swap.amount.min(foreign_amount_pool_denominated); + let done_amount = pool_amount_foreign_denominated + .min(foreign_swap.amount) + .ensure_add(*done_amount)?; + + match swap.amount.cmp(&foreign_amount_pool_denominated) { + // Pool swap amount is immediately fulfilled, i.e. invested and marked as done + // into foreign Ordering::Less => { Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < foreign_swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(pool_amount_foreign_denominated)?, ..*foreign_swap }, done_amount, @@ -314,13 +334,22 @@ impl InvestState }, ) } - // foreign swap amount is immediately invested and done amount increased equally + // Both opposite swaps are immediately fulfilled, i.e. invested and marked as + // done + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap: Swap { + amount: done_amount, + ..*foreign_swap + }, + invest_amount, + }), + // Foreign swap amount is immediately fulfilled, i.e. invested and marked as + // done Ordering::Greater => { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > foreign_swap.amount - amount: swap.amount - foreign_swap.amount, + amount: swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..swap }, done_amount, @@ -338,40 +367,48 @@ impl InvestState invest_amount, } => { swap.ensure_currencies_match(foreign_swap, false)?; + + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_in, + swap.currency_out, + foreign_swap.amount, + )?; + let pool_amount_foreign_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; let invest_amount = - invest_amount.ensure_add(swap.amount.min(foreign_swap.amount))?; - let done_amount = swap - .amount + invest_amount.ensure_add(swap.amount.min(foreign_amount_pool_denominated))?; + let done_amount = pool_amount_foreign_denominated .min(foreign_swap.amount) .ensure_add(*done_amount)?; - match swap.amount.cmp(&foreign_swap.amount) { - // pool swap amount is immediately invested and done amount increased equally - Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { - done_swap: Swap { - amount: done_amount, - ..*foreign_swap - }, - invest_amount, - }), - // swap amount is immediately invested and done amount increased equally + match swap.amount.cmp(&foreign_amount_pool_denominated) { + // Pool swap amount is immediately fulfilled, i.e. invested and marked as done into foreign Ordering::Less => Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount < foreign_swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(pool_amount_foreign_denominated)?, ..*foreign_swap }, done_amount, invest_amount, }, ), - // foreign swap amount is immediately invested and done amount increased equally + // Both opposite swaps are immediately fulfilled, i.e. invested and marked as done + Ordering::Equal => Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap: Swap { + amount: done_amount, + ..*foreign_swap + }, + invest_amount, + }), + // Foreign swap amount is immediately fulfilled, i.e. invested and marked as done Ordering::Greater => Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe since swap.amount > foreign_swap.amount - amount: swap.amount - foreign_swap.amount, + amount: swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..swap }, done_amount, @@ -409,7 +446,6 @@ impl InvestState /// To be safe and to not make any unhandled assumptions, we throw /// `DispatchError::Other` for these states though we need to make sure /// this can never occur! - // FIXME: Currency conversion off fn handle_decrease( &self, swap: Swap, @@ -418,13 +454,6 @@ impl InvestState return Self::handle_decrease_non_foreign(self, swap); } - #[cfg(feature = "std")] - { - println!("handle_decrease"); - // dbg!(&self); - dbg!(&swap); - } - match &self { // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency InvestState::NoState @@ -434,14 +463,17 @@ impl InvestState }, // Increment foreign swap amount up to ongoing investment InvestState::InvestmentOngoing { invest_amount } => { - match swap.amount.cmp(invest_amount) { + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; + + match foreign_amount_pool_denominated.cmp(invest_amount) { Ordering::Less => { Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap: Swap { - amount: T::CurrencyConverter::stable_to_stable(swap.currency_in, swap.currency_out, swap.amount)?, - ..swap - }, - invest_amount: *invest_amount - swap.amount, + swap, + invest_amount: invest_amount.ensure_sub(foreign_amount_pool_denominated)?, }) }, Ordering::Equal => { @@ -457,20 +489,25 @@ impl InvestState InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, false)?; - match swap.amount.cmp(&pool_swap.amount) { - Ordering::Equal => { - Ok(Self::SwapIntoForeignDone { done_swap: swap }) - }, + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; + + match foreign_amount_pool_denominated.cmp(&pool_swap.amount) { Ordering::Less => { Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because swap.amount < pool_swap.amount - amount: pool_swap.amount - swap.amount, + amount: pool_swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..*pool_swap }, done_amount: swap.amount, }) } + Ordering::Equal => { + Ok(Self::SwapIntoForeignDone { done_swap: swap }) + }, // should never occur but let's be safe here Ordering::Greater => { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) @@ -483,51 +520,61 @@ impl InvestState invest_amount, } => { swap.ensure_currencies_match(pool_swap, false)?; - let done_amount = swap.amount.min(pool_swap.amount); - let invest_amount = invest_amount.ensure_sub(done_amount)?; - let max_decrease_amount = pool_swap.amount.ensure_add(invest_amount)?; - #[cfg(feature = "std")]{ - dbg!(&swap.amount, pool_swap.amount, &max_decrease_amount); - } + let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; + let pool_amount_foreign_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_in, + swap.currency_out, + pool_swap.amount, + )?; + let max_decrease_amount_pool_denominated = pool_swap.amount.ensure_add(*invest_amount)?; - if swap.amount < pool_swap.amount { + // Decrease swap into pool + if foreign_amount_pool_denominated < pool_swap.amount { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because done_amount is min - amount: pool_swap.amount - done_amount, + amount: pool_swap.amount.ensure_sub(foreign_amount_pool_denominated)?, ..*pool_swap }, - done_amount, - invest_amount, + done_amount: swap.amount, + invest_amount: *invest_amount, }, ) - } else if swap.amount == pool_swap.amount { + } + // Active swaps cancel out each other + else if foreign_amount_pool_denominated == pool_swap.amount { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, - invest_amount, + invest_amount: *invest_amount, }) - } else if swap.amount < max_decrease_amount { + } + // Decrement exceeds swap into pool and partially ongoing investment + else if foreign_amount_pool_denominated < max_decrease_amount_pool_denominated { Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because done_amount is min - amount: swap.amount - done_amount, + amount: swap.amount.ensure_sub(pool_amount_foreign_denominated)?, ..swap }, - done_amount, - invest_amount, + done_amount: pool_amount_foreign_denominated, + // Foreign swap amount is larger than pool swap amount + invest_amount: max_decrease_amount_pool_denominated.ensure_sub(foreign_amount_pool_denominated)?, }, ) - } else if swap.amount == max_decrease_amount { + } + // Decrement cancels entire swap into pool and ongoing investment + else if swap.amount == max_decrease_amount_pool_denominated { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because done_amount is min - amount: swap.amount - done_amount, + amount: swap.amount.ensure_sub(pool_amount_foreign_denominated)?, ..swap }, - done_amount, + done_amount: pool_amount_foreign_denominated, }) } // should never occur but let's be safe here @@ -541,14 +588,19 @@ impl InvestState invest_amount, } => { swap.ensure_currencies_match(foreign_swap, true)?; + let amount = foreign_swap.amount.ensure_add(swap.amount)?; + let swap_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; - match swap.amount.cmp(invest_amount) { + match swap_amount_pool_denominated.cmp(invest_amount) { Ordering::Less => { Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: Swap { amount, ..swap }, - // safe because invest_amount > swap_amount - invest_amount: *invest_amount - swap.amount, + invest_amount: invest_amount.ensure_sub(swap_amount_pool_denominated)?, }) }, Ordering::Equal => { @@ -568,16 +620,21 @@ impl InvestState invest_amount, } => { swap.ensure_currencies_match(foreign_swap, true)?; + let amount = foreign_swap.amount.ensure_add(swap.amount)?; + let swap_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; - match swap.amount.cmp(invest_amount) { + match swap_amount_pool_denominated.cmp(invest_amount) { Ordering::Less => { Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { amount, ..swap }, done_amount: *done_amount, - // safe because swap.amount < invest_amount - invest_amount: *invest_amount - swap.amount, + invest_amount: invest_amount.ensure_sub(swap_amount_pool_denominated)?, }, ) }, @@ -613,20 +670,18 @@ impl InvestState /// This transition should always increase the active ongoing /// investment. /// - /// NOTE: We can ignore handling all states which include - /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we - /// consume the done amount and transition in the post transition phase. - /// Moreover, we can ignore handling all states which do not include - /// `ActiveSwapInto{Pool, Return}Currency` as else there cannot be an active - /// token swap for investments. - /// To be safe and to not make any unhandled assumptions, we throw - /// `DispatchError::Other` for these states though we need to make sure - /// this can never occur! - - // FIXME(@review): This handler assumes partial fulfillments and 1-to-1 - // conversion of amounts, i.e., 100 `foreign_currency` equals 100 - // `pool_currency`. If we use the CurrencyConverter, the amounts could be off as - // the `CurrencyConverter` is decoupled from the `TokenSwaps` trait. + /// NOTES: + /// * The fulfilled swap will always match the current state (i.e. IntoPool + /// or IntoForeign) and we do not need to denominate amounts into the + /// opposite currency. + /// * We can ignore handling all states which include `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency` as we consume the done amount + /// and transition in the post transition phase. Moreover, we can ignore + /// handling all states which do not include `ActiveSwapInto{Pool, + /// Return}Currency` as else there cannot be an active token swap for + /// investments. To be safe and to not make any unhandled assumptions, we + /// throw `DispatchError::Other` for these states though we need to make + /// sure this can never occur! fn handle_fulfilled_swap_order( &self, swap: Swap, @@ -649,8 +704,7 @@ impl InvestState Ordering::Less => { Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, + amount: pool_swap.amount.ensure_sub(swap.amount)?, ..swap }, invest_amount: swap.amount, @@ -673,8 +727,7 @@ impl InvestState Ordering::Less => { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because foreign_swap.amount > swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(swap.amount)?, ..swap }, done_amount: swap.amount, @@ -701,8 +754,7 @@ impl InvestState Ordering::Less => { Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - // safe because pool_swap.amount > swap.amount - amount: pool_swap.amount - swap.amount, + amount: pool_swap.amount.ensure_sub(swap.amount)?, ..swap }, invest_amount, @@ -732,8 +784,7 @@ impl InvestState Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because foreign_swap.amount > swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(swap.amount)?, ..swap }, done_amount: swap.amount, @@ -767,8 +818,7 @@ impl InvestState Ordering::Less => { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { - // safe because foreign_swap.amount > swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(swap.amount)?, ..swap }, done_amount, @@ -803,8 +853,7 @@ impl InvestState Ok( Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap { - // safe because foreign_swap.amount > swap.amount - amount: foreign_swap.amount - swap.amount, + amount: foreign_swap.amount.ensure_sub(swap.amount)?, ..swap }, done_amount, @@ -868,15 +917,19 @@ impl InvestState /// Handle decrease transitions for the same incoming and outgoing /// currencies. /// - /// NOTE: We can ignore handling all states which include - /// `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` as we - /// consume the done amount and transition in the post transition phase. - /// Moreover, we can ignore any state which involves an active swap, i.e. - /// `ActiveSwapInto{Pool, Return}Currency`, as these must not exist if the - /// in and out currency is the same. - /// To be safe and to not make any unhandled assumptions, we throw - /// `DispatchError::Other` for these states though we need to make sure - /// this can never occur! + /// NOTES: + /// * We can never directly compare `swap.amount` or `done_amount` with + /// `pool_swap.amount` and `invest_amount` if the currencies mismatch as + /// the former pair is denominated in foreign currency and the latter pair + /// in pool currency. + /// * We can ignore handling all states which include `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency` as we consume the done amount + /// and transition in the post transition phase. Moreover, we can ignore + /// any state which involves an active swap, i.e. `ActiveSwapInto{Pool, + /// Return}Currency`, as these must not exist if the in and out currency + /// is the same. To be safe and to not make any unhandled assumptions, we + /// throw `DispatchError::Other` for these states though we need to make + /// sure this can never occur! fn handle_decrease_non_foreign( &self, swap: Swap, @@ -906,7 +959,7 @@ impl InvestState /// * Else the unprocessed amount should be zero. If it is not, state is /// corrupted as this reflects the investment was increased improperly. fn handle_collect(&self, unprocessed_amount: T::Balance) -> Result { - match self.clone() { + match self { Self::InvestmentOngoing { .. } => { if unprocessed_amount.is_zero() { Ok(Self::NoState) @@ -918,20 +971,20 @@ impl InvestState } Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::ActiveSwapIntoPoolCurrency { swap }) + Ok(Self::ActiveSwapIntoPoolCurrency { swap: *swap }) } else { Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap, + swap: *swap, invest_amount: unprocessed_amount, }) } } Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::ActiveSwapIntoForeignCurrency { swap }) + Ok(Self::ActiveSwapIntoForeignCurrency { swap: *swap }) } else { Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap, + swap: *swap, invest_amount: unprocessed_amount, }) } @@ -942,17 +995,15 @@ impl InvestState .. } => { if unprocessed_amount.is_zero() { - Ok( - Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { - swap, - done_amount, - }, - ) + Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { + swap: *swap, + done_amount: *done_amount, + }) } else { Ok( Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap, - done_amount, + swap: *swap, + done_amount: *done_amount, invest_amount: unprocessed_amount, }, ) @@ -960,10 +1011,12 @@ impl InvestState } Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap, .. } => { if unprocessed_amount.is_zero() { - Ok(Self::SwapIntoForeignDone { done_swap }) + Ok(Self::SwapIntoForeignDone { + done_swap: *done_swap, + }) } else { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { - done_swap, + done_swap: *done_swap, invest_amount: unprocessed_amount, }) } @@ -975,20 +1028,20 @@ impl InvestState } => { if unprocessed_amount.is_zero() { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap, - done_amount, + swap: *swap, + done_amount: *done_amount, }) } else { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap, - done_amount, + swap: *swap, + done_amount: *done_amount, invest_amount: unprocessed_amount, }) } } state => { if unprocessed_amount.is_zero() { - Ok(state) + Ok(state.clone()) } else { Err(DispatchError::Other( "Invalid invest state when transitioning epoch execution", diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index d9b3bb5a79..0a16b1cc03 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -55,21 +55,20 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - // Translate amount from foreign to pool_currency - let amount = - T::CurrencyConverter::stable_to_stable(pool_currency, foreign_currency, amount)?; // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( !T::Investment::investment_requires_collect(who, investment_id), Error::::InvestError(InvestError::CollectRequired) ); + let amount_pool_denominated = + T::CurrencyConverter::stable_to_stable(pool_currency, foreign_currency, amount)?; let pre_state = InvestmentState::::get(who, investment_id); let post_state = pre_state .transition(InvestTransition::IncreaseInvestOrder(Swap { currency_in: pool_currency, currency_out: foreign_currency, - amount, + amount: amount_pool_denominated, })) .map_err(|e| { // Inner error holds finer granularity but should never occur @@ -88,17 +87,14 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - // Translate amount from foreign to pool_currency - let amount = - T::CurrencyConverter::stable_to_stable(pool_currency, foreign_currency, amount)?; // TODO(future): Add implicit collection or error handling (i.e. message to // source domain) ensure!( !T::Investment::investment_requires_collect(who, investment_id), Error::::InvestError(InvestError::CollectRequired) ); - let pre_state = InvestmentState::::get(who, investment_id); + let pre_state = InvestmentState::::get(who, investment_id); ensure!( pre_state.get_investing_amount() >= amount, Error::::InvestError(InvestError::Decrease) @@ -113,7 +109,7 @@ impl ForeignInvestment for Pallet { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Increase) + Error::::from(InvestError::Decrease) })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; @@ -391,6 +387,13 @@ impl Pallet { }, } .map(|(invest_state, maybe_swap, invest_amount)| { + // Must update investment amount before handling swap as in case of decrease, + // updating the swap transfers the currency from the investment account to the + // investor which is required for placing the swap order + if T::Investment::investment(who, investment_id)? != invest_amount { + T::Investment::update_investment(who, investment_id, invest_amount)?; + } + let (maybe_invest_state_prio, maybe_new_redeem_state) = Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; // Dispatch transition event, post swap state has priority if it exists as it was the last transition if let Some(invest_state_prio) = maybe_invest_state_prio { @@ -400,11 +403,6 @@ impl Pallet { } Self::deposit_redemption_event(who, investment_id, maybe_new_redeem_state); - if T::Investment::investment(who, investment_id)? != invest_amount { - // Finally, update investment after all states have been updated - T::Investment::update_investment(who, investment_id, invest_amount)?; - } - // Send notification after updating invest as else funds are still locked in investment account if let Some((foreign_currency, decreased_amount)) = maybe_executed_decrease { Self::notify_executed_decrease_invest(who, investment_id, foreign_currency, decreased_amount)?; diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index eb92e4038b..57a9f558da 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -11,11 +11,14 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use cfg_traits::SimpleCurrencyConversion; use cfg_types::investments::Swap; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{dispatch::fmt::Debug, RuntimeDebugNoBound}; use scale_info::TypeInfo; -use sp_runtime::traits::{EnsureAdd, EnsureSub}; +use sp_runtime::traits::{EnsureAdd, EnsureSub, Zero}; + +use crate::Config; /// Reflects the reason for the last token swap update such that it can be /// updated accordingly if the last and current reason mismatch. @@ -27,31 +30,32 @@ pub enum TokenSwapReason { Redemption, } +// TODO: Docs +pub trait InvestStateConfig { + type Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug + Zero; + type CurrencyId: Clone + Copy + PartialEq + Debug; + type CurrencyConverter: SimpleCurrencyConversion< + Balance = Self::Balance, + Currency = Self::CurrencyId, + Error = sp_runtime::DispatchError, + >; +} + +impl InvestStateConfig for T { + type Balance = T::Balance; + type CurrencyConverter = T::CurrencyConverter; + type CurrencyId = T::CurrencyId; +} + /// Reflects all states a foreign investment can have until it is processed as /// an investment via `::Investment`. This includes swapping it /// into a pool currency or back, if the investment is decreased before it is /// fully processed. #[derive( - Clone, - PartialOrd, - Ord, - Copy, - PartialEq, - Eq, - RuntimeDebugNoBound, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, + PartialOrd, Ord, PartialEq, Eq, RuntimeDebugNoBound, Encode, Decode, TypeInfo, MaxEncodedLen, )] -// #[cfg_attr(feature = "std", derive(Debug))] #[scale_info(skip_type_params(T))] -// #[codec(mel_bound())] -pub enum InvestState< - // Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - // Currency: Clone + Copy + PartialEq + Debug, - T: crate::Config, -> { +pub enum InvestState { /// Placeholder state for initialization which will never be stored on /// chain. NoState, @@ -146,13 +150,92 @@ pub enum InvestState< invest_amount: T::Balance, }, } - -impl Default for InvestState { +// NOTE: Needed because `T` of `InvestState` cannot be restricted to impl +// Default +impl Default for InvestState { fn default() -> Self { Self::NoState } } +// NOTE: Needed because `T` of `InvestState` cannot be restricted to impl +// Copy +impl Clone for InvestState +where + T::Balance: Clone, + T::CurrencyId: Clone, + Swap: Clone, +{ + fn clone(&self) -> Self { + match self { + Self::NoState => Self::NoState, + Self::InvestmentOngoing { invest_amount } => Self::InvestmentOngoing { + invest_amount: invest_amount.clone(), + }, + Self::ActiveSwapIntoPoolCurrency { swap } => { + Self::ActiveSwapIntoPoolCurrency { swap: swap.clone() } + } + Self::ActiveSwapIntoForeignCurrency { swap } => { + Self::ActiveSwapIntoForeignCurrency { swap: swap.clone() } + } + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap, + invest_amount, + } => Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: swap.clone(), + invest_amount: invest_amount.clone(), + }, + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap, + invest_amount, + } => Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: swap.clone(), + invest_amount: invest_amount.clone(), + }, + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, done_amount } => { + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { + swap: swap.clone(), + done_amount: done_amount.clone(), + } + } + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: swap.clone(), + done_amount: done_amount.clone(), + } + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount, + } => Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: swap.clone(), + done_amount: done_amount.clone(), + invest_amount: invest_amount.clone(), + }, + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + done_amount, + invest_amount, + } => Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap: swap.clone(), + done_amount: done_amount.clone(), + invest_amount: invest_amount.clone(), + }, + Self::SwapIntoForeignDone { done_swap } => Self::SwapIntoForeignDone { + done_swap: done_swap.clone(), + }, + Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap, + invest_amount, + } => Self::SwapIntoForeignDoneAndInvestmentOngoing { + done_swap: done_swap.clone(), + invest_amount: invest_amount.clone(), + }, + } + } +} + /// Reflects all state transitions of an `InvestmentState` which can be /// externally triggered, i.e. by (partially) fulfilling a token swap order or /// updating an unprocessed investment. @@ -161,9 +244,11 @@ pub enum InvestTransition< Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, Currency: Clone + Copy + PartialEq + Debug, > { - /// Assumes `swap.currency_in` is pool currency as we increase here. + /// Assumes `swap.amount` to be denominated in pool currency and + /// `swap.currency_in` to be pool currency as we increase here. IncreaseInvestOrder(Swap), - /// Assumes `swap.currency_in` is foreign currency as we decrease here. + /// Assumes `swap.amount` to be denominated in foreign currency and + /// `swap.currency_in` to be foreign currency as we increase here. DecreaseInvestOrder(Swap), /// Implicitly derives `swap.currency_in` and `swap.currency_out` from /// previous state: diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index 1a03bb1ea4..c5d95687de 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -471,11 +471,6 @@ pub mod pallet { currency_out: T::AssetCurrencyId, buy_amount: T::Balance, ) -> DispatchResult { - #[cfg(feature = "std")] - { - dbg!(T::MinimumOrderAmount::get(&(currency_in, currency_out))); - dbg!(buy_amount); - } match T::MinimumOrderAmount::get(&(currency_in, currency_out)) { Some(amount) if amount <= buy_amount => Ok(()), None => Err(Error::::InvalidTradingPair)?, @@ -497,11 +492,6 @@ pub mod pallet { .ok_or(Error::::InvalidAssetId)? .decimals; - #[cfg(feature = "std")] - { - dbg!(from_decimals); - dbg!(to_decimals); - } // FIXME: Maybe. This equals 10^(to - from) * to_amount when it should be // multiplied with from_amount? Or convert_balance_decimals(from_decimals, to_decimals, ratio.ensure_mul_int(amount)?) @@ -561,28 +551,8 @@ pub mod pallet { let max_sell_amount = Self::convert_with_ratio(currency_in, currency_out, sell_rate_limit, buy_amount)?; - #[cfg(feature = "std")] - { - dbg!(T::TradeableAsset::balance(currency_out, &account)); - dbg!(T::TradeableAsset::balance(currency_in, &account)); - dbg!(&buy_amount, &max_sell_amount, sell_rate_limit); - } - - #[cfg(feature = "std")] - { - dbg!( - "before holding", - T::TradeableAsset::balance(currency_out, &account) > max_sell_amount - ); - } - T::TradeableAsset::hold(currency_out, &account, max_sell_amount)?; - #[cfg(feature = "std")] - { - println!("after holding",); - } - let order_id = >::get(); let new_order = Order { order_id, @@ -602,16 +572,6 @@ pub mod pallet { .map_err(|_| Error::::AssetPairOrdersOverflow) })?; - #[cfg(feature = "std")] - { - dbg!( - "create order", - currency_in, - currency_out, - AssetPairOrders::::get(currency_in, currency_out) - ); - } - >::insert(order_id, new_order.clone()); >::insert(&account, order_id, new_order); Self::deposit_event(Event::OrderCreated { diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 1c534e87b4..217ee276a6 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1891,10 +1891,6 @@ const MIN_DEV_NATIVE_ORDER: u128 = DEFAULT_DEV_MIN_ORDER * CFG; parameter_type_with_key! { pub MinimumOrderAmount: |pair: (CurrencyId, CurrencyId)| -> Option { - #[cfg(feature = "std")]{ - dbg!(&pair); - dbg!(MIN_DEV_AUSD_ORDER); - } match pair { (CurrencyId::Native, DEV_AUSD_CURRENCY_ID) => Some(MIN_DEV_NATIVE_ORDER), (DEV_AUSD_CURRENCY_ID, CurrencyId::Native) => Some(MIN_DEV_AUSD_ORDER), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 609c4437c8..438687b8aa 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -21,3 +21,1345 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. + +use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; +use cfg_traits::{ + investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + liquidity_pools::InboundQueue, +}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + investments::{InvestCollection, InvestmentAccount, RedeemCollection}, + orders::FulfillmentWithPrice, + permissions::{PermissionScope, PoolRole, Role, UNION}, + pools::TrancheMetadata, + tokens::{ + CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, + ForeignAssetId, + }, +}; +use development_runtime::{ + Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, OrmlTokens, + Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, System, +}; +use frame_support::{ + assert_noop, assert_ok, + traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, +}; +use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; +use pallet_investments::CollectOutcome; +use runtime_common::account_conversion::AccountConverter; +use sp_runtime::{ + traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, + BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, +}; +use xcm_emulator::TestExt; + +use crate::{ + liquidity_pools::pallet::development::{ + setup::{dollar, ALICE, BOB}, + test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::liquidity_pools::{ + foreign_investments::setup::{ + do_initial_increase_investment, do_initial_increase_redemption, + }, + setup::{ + asset_metadata, create_ausd_pool, create_currency_pool, + enable_liquidity_pool_transferability, + investments::{ + default_investment_account, default_investment_id, default_tranche_id, + general_currency_index, investment_id, + }, + setup_pre_requirements, LiquidityPoolMessage, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + DEFAULT_POOL_ID, DEFAULT_VALIDITY, + }, + }, + }, + utils::AUSD_CURRENCY_ID, +}; + +mod same_currencies { + use super::*; +} + +#[test] +fn inbound_increase_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor, currency_id); + + // Verify the order was updated to the amount + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + amount + ); + }); +} + +#[test] +fn inbound_decrease_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let decrease_amount = invest_amount / 3; + let final_amount = invest_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + enable_liquidity_pool_transferability(currency_id); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + final_amount + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); +} + +#[test] +fn inbound_cancel_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + + // Verify investment account holds funds before cancelling + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + invest_amount + ); + + // Mock incoming cancel message + let msg = LiquidityPoolMessage::CancelInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable + ); + enable_liquidity_pool_transferability(currency_id); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Foreign InvestmentState should be cleared + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(&investor, default_investment_id())); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + + // Verify investment was entirely drained from investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + 0 + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: invest_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); +} + +#[test] +fn inbound_collect_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + let investment_currency_id: CurrencyId = default_investment_id().into(); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::InvestCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_invest_orders(default_investment_id())); + + // Tranche tokens will be minted upon fulfillment + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); + + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify investment was transferred to the domain locator + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + amount + ); + + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign CollectedInvestment should be killed + assert!(!pallet_foreign_investments::CollectedInvestment::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Foreign InvestmentState should be killed + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Clearing of foreign InvestState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + }); +} + +#[test] +fn inbound_increase_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, amount, investor, currency_id); + + // Verify amount was noted in the corresponding order + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + amount + ); + + // increase again, state should be SwapIntoForeignDone + }); +} + +#[test] +fn inbound_decrease_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let decrease_amount = redeem_amount / 3; + let final_amount = redeem_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); + + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + final_amount + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + decrease_amount + ); + + // Foreign RedemptionState should be updated + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::InvestedAnd { + invest_amount: decrease_amount, + inner: InnerRedeemState::Redeeming { + redeem_amount: final_amount + } + } + } + .into() + })); + + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); +} + +#[test] +fn inbound_cancel_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); + + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::CancelRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + redeem_amount + ); + + // Foreign RedemptionState should be updated + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::Invested { invest_amount: redeem_amount }, + } + .into() + })); + + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); +} + +#[test] +fn inbound_collect_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::RedeemCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Enable liquidity pool transferability + enable_liquidity_pool_transferability(currency_id); + + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); + + // Verify collected redemption was burned from investor + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount + } + .into())); + + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: amount, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign CollectedRedemptionTrancheTokens should be killed + assert!(!pallet_foreign_investments::CollectedRedemption::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id(),)); + + // Foreign RedemptionState should be killed + assert!(!pallet_foreign_investments::RedemptionState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Clearing of foreign RedeemState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + }); +} + +mod should_fail { + use pallet_foreign_investments::errors::{InvestError, RedeemError}; + + use super::*; + + mod decrease_should_underflow { + use super::*; + + #[test] + fn invest_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let decrease_amount = invest_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability(currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::Decrease + ) + ); + }); + } + + #[test] + fn redeem_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount: u128 = 100_000_000; + let decrease_amount = redeem_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption( + pool_id, + redeem_amount, + investor.clone(), + currency_id, + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::Decrease + ) + ); + }); + } + } + + mod should_throw_requires_collect { + use super::*; + #[test] + fn invest_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + }); + } + + #[test] + fn redeem_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Mint more into DomainLocator required for subsequent invest attempt + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + 1, + )); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + }); + } + } +} + +mod mismatching_currencies { + use cfg_traits::SimpleCurrencyConversion; + use cfg_types::investments::Swap; + use development_runtime::{DefaultTokenSellRate, OrderBook, StableToStableRate}; + use pallet_foreign_investments::InvestmentState; + use runtime_common::foreign_investments::SimpleStableCurrencyConverter; + + use super::*; + use crate::{ + liquidity_pools::pallet::development::tests::register_usdt, + utils::{GLMR_CURRENCY_ID, USDT_CURRENCY_ID}, + }; + + /// Invest in pool currency, then increase in allowed foreign currency, then + /// decrease in same foreign currency multiple times. + #[test] + fn invest_increase_decrease() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = BOB.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 6_000_000_000_000_000; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + do_initial_increase_investment( + pool_id, + invest_amount_pool_denominated, + investor.clone(), + pool_currency, + ); + + // USDT investment preparations + register_usdt(); + let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); + + // Should fail to increase to an invalid payment currency + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg.clone()), + pallet_liquidity_pools::Error::::InvalidPaymentCurrency + ); + + // Create counter order (pool to foreign) such that foreign_currency is accepted + // as payment + assert_ok!(OrmlTokens::mint_into( + pool_currency, + &ALICE.into(), + invest_amount_pool_denominated + )); + assert_ok!(OrderBook::create_order( + RuntimeOrigin::signed(ALICE.into()), + foreign_currency, + pool_currency, + invest_amount_foreign_denominated, + DefaultTokenSellRate::get() + )); + + // Should be able to invest since InvestmentState does not have an active swap, + // i.e. any tradable pair is allowed to invest at this point + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + increase_msg + )); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: invest_amount_pool_denominated, + currency_in: pool_currency, + currency_out: foreign_currency, + }, + invest_amount: invest_amount_pool_denominated + }, + } + .into() + })); + + // Should be able to to decrease in the swapping foreign currency + enable_liquidity_pool_transferability(foreign_currency); + let decrease_msg_pool_swap_amount = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_pool_swap_amount + )); + // Entire swap amount into pool currency should be nullified + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated + } + ); + // assert!(System::events().iter().any(|e| { + // e.event == + // pallet_foreign_investments::Event::::ForeignInvestmentUpdated + // { investor: investor.clone(), + // investment_id: default_investment_id(), + // state: InvestState::InvestmentOngoing { + // invest_amount: invest_amount_foreign_denominated + // }, + // } + // .into() + // })); + + // Decrease partial investing amount + enable_liquidity_pool_transferability(foreign_currency); + let decrease_msg_partial_invest_amount = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated / 2, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_partial_invest_amount.clone() + )); + // Decreased amount should be taken from investing amount + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: Swap { + amount: invest_amount_foreign_denominated / 2, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + invest_amount: invest_amount_pool_denominated / 2 + } + ); + // assert!(System::events().iter().any(|e| { + // e.event == + // pallet_foreign_investments::Event::::ForeignInvestmentUpdated + // { investor: investor.clone(), + // investment_id: default_investment_id(), + // state: InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + // swap: Swap { + // amount: invest_amount_foreign_denominated / 2, + // currency_in: foreign_currency, + // currency_out: pool_currency, + // }, + // invest_amount: invest_amount_foreign_denominated / 2 + // }, + // } + // .into() + // })); + + /// Consume entire investing amount by sending same message + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + decrease_msg_partial_invest_amount.clone() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::::ActiveSwapIntoForeignCurrency { + swap: Swap { + amount: invest_amount_foreign_denominated, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + } + ); + // assert!(System::events().iter().any(|e| { + // e.event == + // pallet_foreign_investments::Event::::ForeignInvestmentUpdated + // { investor: investor.clone(), + // investment_id: default_investment_id(), + // state: InvestState::ActiveSwapIntoForeignCurrency { + // swap: Swap { + // amount: invest_amount_foreign_denominated, + // currency_in: foreign_currency, + // currency_out: pool_currency, + // } + // }, + // } + // .into() + // })); + }); + } + + // TODO: Similar tests for decreasing investments, increase/decrease and + // collect redemption +} + +mod setup { + use super::*; + use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; + + /// Sets up required permissions for the investor and executes an + /// initial investment via LiquidityPools by executing + /// `IncreaseInvestOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand + pub fn do_initial_increase_investment( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let valid_until = DEFAULT_VALIDITY; + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + + // Should fail if investor does not have investor role yet + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + + // Make investor the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + investor.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + let amount_before = OrmlTokens::free_balance(currency_id, &default_investment_account()); + let final_amount = amount_before + .ensure_add(amount) + .expect("Should not overflow when incrementing amount"); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was transferred into investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + final_amount + ); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: InvestState::InvestmentOngoing { + invest_amount: final_amount + }, + } + .into() + })); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount, + } + .into() + })); + } + + /// Sets up required permissions for the investor and executes an + /// initial redemption via LiquidityPools by executing + /// `IncreaseRedeemOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand. + /// + /// NOTE: Mints exactly the redeeming amount of tranche tokens. + pub fn do_initial_increase_redemption( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let valid_until = DEFAULT_VALIDITY; + + // Fund `DomainLocator` account of origination domain as redeemed tranche tokens + // are transferred from this account instead of minting + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount + )); + + // Verify redemption has not been made yet + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id: 42, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + + // Should fail if investor does not have investor role yet + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + + // Make investor the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + investor.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify redemption was transferred into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + amount + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) + ), + 0 + ); + assert_eq!( + System::events().iter().nth_back(4).unwrap().event, + pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: amount + } + }, + } + .into() + ); + assert_eq!( + System::events().iter().last().unwrap().event, + pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor, + amount + } + .into() + ); + + // Verify order id is 0 + assert_eq!( + pallet_investments::Pallet::::redeem_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); + } +} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs index 7c63daf94e..e8e509c216 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/mod.rs @@ -24,7 +24,6 @@ mod add_allow_upgrade; mod foreign_investments; -mod non_foreign_investments; mod setup; mod transfers; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs deleted file mode 100644 index 74c6f244bd..0000000000 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/non_foreign_investments.rs +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// Copyright 2021 Centrifuge GmbH (centrifuge.io). -// This file is part of Centrifuge chain project. -// -// Centrifuge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version (see http://www.gnu.org/licenses). -// Centrifuge is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; -use cfg_traits::{ - investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, - liquidity_pools::InboundQueue, -}; -use cfg_types::{ - domain_address::{Domain, DomainAddress}, - fixed_point::Rate, - investments::{InvestCollection, InvestmentAccount, RedeemCollection}, - orders::FulfillmentWithPrice, - permissions::{PermissionScope, PoolRole, Role, UNION}, - pools::TrancheMetadata, - tokens::{ - CrossChainTransferability, CurrencyId, CurrencyId::ForeignAsset, CustomMetadata, - ForeignAssetId, - }, -}; -use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, OrmlTokens, - Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, System, -}; -use frame_support::{ - assert_noop, assert_ok, - traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, -}; -use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; -use pallet_investments::CollectOutcome; -use runtime_common::account_conversion::AccountConverter; -use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, - BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, -}; -use xcm_emulator::TestExt; - -use crate::{ - liquidity_pools::pallet::development::{ - setup::{dollar, ALICE, BOB}, - test_net::{Development, Moonbeam, RelayChain, TestNet}, - tests::liquidity_pools::{ - non_foreign_investments::setup::{ - do_initial_increase_investment, do_initial_increase_redemption, - }, - setup::{ - asset_metadata, create_ausd_pool, create_currency_pool, - enable_liquidity_pool_transferability, - investments::{ - default_investment_account, default_investment_id, default_tranche_id, - general_currency_index, investment_id, - }, - setup_pre_requirements, LiquidityPoolMessage, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - DEFAULT_POOL_ID, DEFAULT_VALIDITY, - }, - }, - }, - utils::AUSD_CURRENCY_ID, -}; - -#[test] -fn inbound_increase_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, amount, investor, currency_id); - - // Verify the order was updated to the amount - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - amount - ); - }); -} - -#[test] -fn inbound_decrease_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount: u128 = 100_000_000; - let decrease_amount = invest_amount / 3; - let final_amount = invest_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - enable_liquidity_pool_transferability(currency_id); - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - final_amount - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: decrease_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); -} - -#[test] -fn inbound_cancel_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); - - // Verify investment account holds funds before cancelling - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - invest_amount - ); - - // Mock incoming cancel message - let msg = LiquidityPoolMessage::CancelInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable - ); - enable_liquidity_pool_transferability(currency_id); - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Foreign InvestmentState should be cleared - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(&investor, default_investment_id())); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - - // Verify investment was entirely drained from investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - 0 - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: invest_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - }); -} - -#[test] -fn inbound_collect_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - let investment_currency_id: CurrencyId = default_investment_id().into(); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); - let events_before_collect = System::events(); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_invest_orders(default_investment_id())); - - // Tranche tokens will be minted upon fulfillment - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); - - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); - - // Verify investment was transferred to the domain locator - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - amount - ); - - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: default_investment_id(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - // Foreign CollectedInvestment should be killed - assert!(!pallet_foreign_investments::CollectedInvestment::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Foreign InvestmentState should be killed - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Clearing of foreign InvestState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignInvestmentCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - }); -} - -#[test] -fn inbound_increase_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, amount, investor, currency_id); - - // Verify amount was noted in the corresponding order - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - amount - ); - - // increase again, state should be SwapIntoForeignDone - }); -} - -#[test] -fn inbound_decrease_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount = 100_000_000; - let decrease_amount = redeem_amount / 3; - let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - final_amount - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - decrease_amount - ); - - // Foreign RedemptionState should be updated - assert!(System::events().iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: RedeemState::InvestedAnd { - invest_amount: decrease_amount, - inner: InnerRedeemState::Redeeming { - redeem_amount: final_amount - } - } - } - .into() - })); - - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); -} - -#[test] -fn inbound_cancel_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::CancelRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - 0 - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - redeem_amount - ); - - // Foreign RedemptionState should be updated - assert!(System::events().iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: RedeemState::Invested { invest_amount: redeem_amount }, - } - .into() - })); - - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - 0 - ); - }); -} - -#[test] -fn inbound_collect_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); - let events_before_collect = System::events(); - - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_redeem_orders(default_investment_id())); - assert_ok!(Investments::redeem_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - - // Enable liquidity pool transferability - enable_liquidity_pool_transferability(currency_id); - - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); - - // Verify collected redemption was burned from investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount - } - .into())); - - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { - investment_id: default_investment_id(), - who: investor.clone(), - } - .into() - })); - - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); - - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: amount, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - // Foreign CollectedRedemptionTrancheTokens should be killed - assert!(!pallet_foreign_investments::CollectedRedemption::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id(),)); - - // Foreign RedemptionState should be killed - assert!(!pallet_foreign_investments::RedemptionState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Clearing of foreign RedeemState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - })); - }); -} - -mod should_fail { - use pallet_foreign_investments::errors::{InvestError, RedeemError}; - - use super::*; - - mod decrease_should_underflow { - use super::*; - - #[test] - fn invest_decrease_underflow() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount: u128 = 100_000_000; - let decrease_amount = invest_amount + 1; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability(currency_id); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::Decrease - ) - ); - }); - } - - #[test] - fn redeem_decrease_underflow() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount: u128 = 100_000_000; - let decrease_amount = redeem_amount + 1; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_redemption( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::Decrease - ) - ); - }); - } - } - - mod should_throw_requires_collect { - use super::*; - #[test] - fn invest_requires_collect() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); - enable_liquidity_pool_transferability(currency_id); - - // Prepare collection - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - assert_ok!(Investments::process_invest_orders(default_investment_id())); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::CollectRequired - ) - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::CollectRequired - ) - ); - }); - } - - #[test] - fn redeem_requires_collect() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); - enable_liquidity_pool_transferability(currency_id); - - // Mint more into DomainLocator required for subsequent invest attempt - assert_ok!(OrmlTokens::mint_into( - default_investment_id().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - 1, - )); - - // Prepare collection - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - assert_ok!(Investments::process_redeem_orders(default_investment_id())); - assert_ok!(Investments::redeem_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::CollectRequired - ) - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::CollectRequired - ) - ); - }); - } - } - - mod mismatching_currencies { - use cfg_traits::SimpleCurrencyConversion; - use development_runtime::{DefaultTokenSellRate, OrderBook, StableToStableRate}; - use runtime_common::foreign_investments::SimpleStableCurrencyConverter; - - use super::*; - use crate::{ - liquidity_pools::pallet::development::tests::register_usdt, - utils::{GLMR_CURRENCY_ID, USDT_CURRENCY_ID}, - }; - - #[test] - fn invest_increase_another_currency() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let investor: AccountId = BOB.into(); - let pool_currency: CurrencyId = AUSD_CURRENCY_ID; - let foreign_currency: CurrencyId = USDT_CURRENCY_ID; - let pool_currency_decimals = currency_decimals::AUSD; - let invest_amount_pool_currency: u128 = 5_000_000_000_000; - create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); - do_initial_increase_investment( - pool_id, - invest_amount_pool_currency, - investor.clone(), - pool_currency, - ); - - // USDT investment preparations - register_usdt(); - let invest_amount_foreign_currency: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRate, - >::stable_to_stable( - foreign_currency, - pool_currency, - invest_amount_pool_currency, - ) - .unwrap(); - assert_ok!(OrmlTokens::mint_into( - pool_currency, - &ALICE.into(), - invest_amount_pool_currency - )); - - // Should fail to increase to an invalid payment currency - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(foreign_currency), - amount: invest_amount_foreign_currency, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg.clone()), - pallet_liquidity_pools::Error::::InvalidPaymentCurrency - ); - - // Create counter order (pool to foreign) such that foreign_currency is accepted - // as payment - assert_ok!(OrderBook::create_order( - RuntimeOrigin::signed(ALICE.into()), - foreign_currency, - pool_currency, - invest_amount_foreign_currency, - DefaultTokenSellRate::get() - )); - assert_ok!(LiquidityPools::submit( - DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - increase_msg - ),); - - // Should fail to decrease in another currency - enable_liquidity_pool_transferability(foreign_currency); - let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(foreign_currency), - amount: invest_amount_foreign_currency, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::Decrease - ) - ); - }); - } - - // TODO: Similar tests for decreasing investments, increase/decrease and - // collect redemption - } -} - -mod setup { - use super::*; - use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; - - /// Sets up required permissions for the investor and executes an - /// initial investment via LiquidityPools by executing - /// `IncreaseInvestOrder`. - /// - /// Assumes `setup_pre_requirements` and - /// `investments::create_currency_pool` to have been called - /// beforehand - pub fn do_initial_increase_investment( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let valid_until = DEFAULT_VALIDITY; - - // Mock incoming increase invest message - let msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount, - }; - - // Should fail if investor does not have investor role yet - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - - // Make investor the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - investor.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - let amount_before = OrmlTokens::free_balance(currency_id, &default_investment_account()); - let final_amount = amount_before - .ensure_add(amount) - .expect("Should not overflow when incrementing amount"); - - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Verify investment was transferred into investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - final_amount - ); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: InvestState::InvestmentOngoing { - invest_amount: final_amount - }, - } - .into() - })); - assert_eq!( - System::events().iter().last().unwrap().event, - pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor, - amount: final_amount - } - .into() - ); - } - - /// Sets up required permissions for the investor and executes an - /// initial redemption via LiquidityPools by executing - /// `IncreaseRedeemOrder`. - /// - /// Assumes `setup_pre_requirements` and - /// `investments::create_currency_pool` to have been called - /// beforehand. - /// - /// NOTE: Mints exactly the redeeming amount of tranche tokens. - pub fn do_initial_increase_redemption( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let valid_until = DEFAULT_VALIDITY; - - // Fund `DomainLocator` account of origination domain as redeemed tranche tokens - // are transferred from this account instead of minting - assert_ok!(OrmlTokens::mint_into( - default_investment_id().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - amount - )); - - // Verify redemption has not been made yet - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - - // Mock incoming increase invest message - let msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id: 42, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount, - }; - - // Should fail if investor does not have investor role yet - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - - // Make investor the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - investor.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); - - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - - // Verify redemption was transferred into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - amount - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) - ), - 0 - ); - assert_eq!( - System::events().iter().nth_back(4).unwrap().event, - pallet_foreign_investments::Event::::ForeignRedemptionUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: amount - } - }, - } - .into() - ); - assert_eq!( - System::events().iter().last().unwrap().event, - pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor, - amount - } - .into() - ); - - // Verify order id is 0 - assert_eq!( - pallet_investments::Pallet::::redeem_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); - } -} From a3097370c60be31010fda5b7849893347c7b445f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 18:53:48 +0200 Subject: [PATCH 66/96] fix: apply foreign denominations to collect redeem, handle swap orders --- pallets/foreign-investments/src/errors.rs | 7 + .../foreign-investments/src/impls/invest.rs | 68 +++++++--- pallets/foreign-investments/src/impls/mod.rs | 123 ++++++++++++------ pallets/foreign-investments/src/types.rs | 10 +- pallets/investments/src/lib.rs | 4 +- 5 files changed, 146 insertions(+), 66 deletions(-) diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index cb9659eb36..09aa4efc27 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -39,6 +39,13 @@ pub enum RedeemError { Increase, /// Failed to collect the redemption. Collect, + /// Failed to retrieve the foreign payout currency for a collected + /// redemption. + /// + /// NOTE: This error can only occur, if a user tries to collect before + /// having increased their redemption as this would store the payout + /// currency. + CollectPayoutCurrencyNotFound, /// Failed to decrease the unprocessed redemption. Decrease, /// Failed to transition after fulfilled swap order. diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index f4234923fb..e9f637a643 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -51,29 +51,63 @@ where } } - /// Returns the potentially existing active swap into either pool or return + /// Returns the potentially existing active swap amount denominated in pool /// currency: - /// * If the state includes `ActiveSwapInto{Pool, Return}Currency`, it - /// returns `Some(swap)`. + /// * If the state includes `ActiveSwapIntoPoolCurrency`, it returns + /// `Some(swap.amount)`. + /// * If the state includes `ActiveSwapIntoForeignCurrency`, it returns + /// `Some(swap.amount)` converted into pool currency denomination. /// * Else, it returns `None`. - pub(crate) fn get_active_swap(&self) -> Option> { + pub(crate) fn get_active_swap_amount_pool_denominated( + &self, + ) -> Result { + match *self { + InvestState::NoState => Ok(T::Balance::zero()), + InvestState::InvestmentOngoing { .. } => Ok(T::Balance::zero()), + InvestState::ActiveSwapIntoPoolCurrency { swap } => Ok(swap.amount), + InvestState::ActiveSwapIntoForeignCurrency { swap } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(swap.amount), + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { + Ok(swap.amount) + }, + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { + Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?) + }, + InvestState::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), + InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), + } + } + + /// Returns the potentially existing active swap amount denominated in + /// foreign currency: + /// * If the state includes `ActiveSwapIntoPoolCurrency`, it returns + /// `Some(swap.amount)` converted into foreign currency denomination. + /// * If the state includes `ActiveSwapIntoForeignCurrency`, it returns + /// `Some(swap.amount)`. + /// * Else, it returns `None`. + pub(crate) fn get_active_swap_amount_foreign_denominated( + &self, + ) -> Result { match *self { - InvestState::NoState => None, - InvestState::InvestmentOngoing { .. } => None, - InvestState::ActiveSwapIntoPoolCurrency { swap } => Some(swap), - InvestState::ActiveSwapIntoForeignCurrency { swap } => Some(swap), - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + InvestState::NoState => Ok(T::Balance::zero()), + InvestState::InvestmentOngoing { .. } => Ok(T::Balance::zero()), + InvestState::ActiveSwapIntoPoolCurrency { swap } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoForeignCurrency { swap } => Ok(swap.amount), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), + InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), + InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(swap.amount), InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { - Some(swap) + Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?) }, InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { - Some(swap) + Ok(swap.amount) }, - InvestState::SwapIntoForeignDone { .. } => None, - InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => None, + InvestState::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), + InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), } } @@ -121,7 +155,7 @@ where /// /// Example: /// * Say before my pre invest state has `foreign_done = 1000` and - /// `foreign_swap.amount = 500`. Now we look at three scenarios in which we + /// `foreign_swap.amount = 500`. Now we look at three scenarios in which we /// increase below, exactly at and above the `foreign_swap.amount`: /// * a) If we increase by 500, we can reduce the `foreign_swap.amount` /// fully, which we denote by adding the 500 to the `foreign_done` amount. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 0a16b1cc03..3a7dc19c14 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -22,7 +22,7 @@ use cfg_types::investments::{ }; use frame_support::{ensure, traits::Get, transactional}; use sp_runtime::{ - traits::{EnsureAdd, EnsureAddAssign, Zero}, + traits::{EnsureAdd, EnsureAddAssign, EnsureSub, Zero}, DispatchError, DispatchResult, }; @@ -873,40 +873,56 @@ impl Pallet { return Ok((None, None, None)); } - // Read states from storage and determine amounts + // Read states from storage and determine amounts in possible denominations let invest_state = InvestmentState::::get(who, investment_id); let redeem_state = RedemptionState::::get(who, investment_id); - let invest_swap_amount = invest_state + let invest_swap_amount_pool_deno = + invest_state.get_active_swap_amount_pool_denominated()?; + let invest_swap_amount_foreign_deno = + invest_state.get_active_swap_amount_foreign_denominated()?; + let (redeem_swap_amount_foreign_deno, redeem_swap_amount_pool_deno) = redeem_state .get_active_swap() - .map(|s| s.amount) - .unwrap_or_default(); - let redeem_swap_amount = redeem_state - .get_active_swap() - .map(|s| s.amount) + .map(|swap| { + // Redemptions can only swap into foreign + let amount_pool_denominated = T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?; + Ok::<(T::Balance, T::Balance), DispatchError>(( + swap.amount, + amount_pool_denominated, + )) + }) + .transpose()? .unwrap_or_default(); - let resolved_amount = invest_swap_amount.min(redeem_swap_amount); - // safe because max >= min, equals zero if both amounts equal - let swap_amount_opposite_direction = - invest_swap_amount.max(redeem_swap_amount) - resolved_amount; + let resolved_amount_pool_deno = + invest_swap_amount_pool_deno.min(redeem_swap_amount_pool_deno); + let swap_amount_opposite_direction_pool_deno = invest_swap_amount_pool_deno + .max(redeem_swap_amount_pool_deno) + .ensure_sub(resolved_amount_pool_deno)?; + let swap_amount_opposite_direction_foreign_deno = invest_swap_amount_foreign_deno + .max(redeem_swap_amount_foreign_deno) + .ensure_sub(invest_swap_amount_foreign_deno.min(redeem_swap_amount_foreign_deno))?; // Determine new invest state let new_invest_state = match invest_state { // As redeem swap can only be into foreign currency, we need to delta on the opposite // swap directions InvestState::ActiveSwapIntoPoolCurrency { swap } => { - if invest_swap_amount > redeem_swap_amount { + if invest_swap_amount_pool_deno > redeem_swap_amount_pool_deno { Some( InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - amount: swap_amount_opposite_direction, + amount: swap_amount_opposite_direction_pool_deno, ..swap }, - invest_amount: resolved_amount, + invest_amount: resolved_amount_pool_deno, }, ) } else { Some(InvestState::InvestmentOngoing { - invest_amount: resolved_amount, + invest_amount: resolved_amount_pool_deno, }) } } @@ -915,19 +931,19 @@ impl Pallet { swap: invest_swap, invest_amount, } => { - if invest_swap_amount > redeem_swap_amount { + if invest_swap_amount_pool_deno > redeem_swap_amount_pool_deno { Some( InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: Swap { - amount: swap_amount_opposite_direction, + amount: swap_amount_opposite_direction_pool_deno, ..invest_swap }, - invest_amount: invest_amount.ensure_add(resolved_amount)?, + invest_amount: invest_amount.ensure_add(resolved_amount_pool_deno)?, }, ) } else { Some(InvestState::InvestmentOngoing { - invest_amount: invest_amount.ensure_add(resolved_amount)?, + invest_amount: invest_amount.ensure_add(resolved_amount_pool_deno)?, }) } } @@ -936,52 +952,64 @@ impl Pallet { }; // Determine final swap amount and new redeem state - let (final_swap_amount, new_redeem_state) = match invest_state { + let (final_swap_amount_foreign_deno, new_redeem_state) = match invest_state { // Opposite swaps cancel out at least one (or if equal amounts) both swaps InvestState::ActiveSwapIntoPoolCurrency { .. } | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } => { let new_state = redeem_state .fulfill_active_swap_amount( - redeem_swap_amount.min(swap_amount_opposite_direction), + redeem_swap_amount_foreign_deno + .min(swap_amount_opposite_direction_foreign_deno), ) .unwrap_or(redeem_state); - Ok((swap_amount_opposite_direction, new_state)) + Ok((swap_amount_opposite_direction_foreign_deno, new_state)) } // All leftover combinations either do not involve any active swaps or both // swaps have the same direction, i.e. into foreign currency. Thus, we can // leave states untouched and just add up the potential swap amount. _ => Ok(( - invest_swap_amount.ensure_add(redeem_swap_amount)?, + invest_swap_amount_foreign_deno.ensure_add(redeem_swap_amount_foreign_deno)?, redeem_state, )), } - .map(|(token_swap_amount, maybe_new_redeem_state)| { + .map(|(token_swap_amount_foreign_deno, maybe_new_redeem_state)| { // If old state match new state, no need to return it as this could cause a // follow-up transition trigger if redeem_state == maybe_new_redeem_state { - (token_swap_amount, None) + (token_swap_amount_foreign_deno, None) } else { - (token_swap_amount, Some(maybe_new_redeem_state)) + (token_swap_amount_foreign_deno, Some(maybe_new_redeem_state)) } }) .map_err(|e: DispatchError| e)?; // Determine token swap from amount - let token_swap = if invest_swap_amount > redeem_swap_amount { - invest_state.get_active_swap().map(|invest_swap| Swap { - amount: final_swap_amount, - ..invest_swap - }) - } - // handle redeem_swap_amount >= invest_swap_amount as well as all cases, in which neither - // states include an active swap - else { - redeem_state.get_active_swap().map(|redeem_swap| Swap { - amount: final_swap_amount, - ..redeem_swap + let token_swap = redeem_state + .get_active_swap() + .map(|swap| { + if invest_swap_amount_foreign_deno > redeem_swap_amount_foreign_deno { + Ok(Swap { + amount: T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + final_swap_amount_foreign_deno, + )?, + currency_in: swap.currency_out, + currency_out: swap.currency_in, + }) + } + // handle redeem_swap_amount >= invest_swap_amount as well as all cases, in which + // neither states include an active swap + else { + Ok(Swap { + amount: final_swap_amount_foreign_deno, + ..swap + }) + } }) - }; + .transpose() + .map_err(|e: DispatchError| e)?; Ok((token_swap, new_invest_state, new_redeem_state)) } @@ -1061,8 +1089,10 @@ impl Pallet { investment_id: T::InvestmentId, collected: CollectedAmount, ) -> DispatchResult { - let foreign_payout_currency = - RedemptionPayoutCurrency::::get(who, investment_id).expect("Foreign redemption payout currency is set by initial increment before collecting is possible"); + let foreign_payout_currency = RedemptionPayoutCurrency::::get(who, investment_id) + .ok_or(Error::::RedeemError( + RedeemError::CollectPayoutCurrencyNotFound, + ))?; let pool_currency = T::PoolInspect::currency_for(investment_id.of_pool()) .expect("Impossible to collect redemption for non existing pool at this point"); @@ -1080,11 +1110,18 @@ impl Pallet { // Transition state to initiate swap from pool to foreign currency let pre_state = RedemptionState::::get(who, investment_id); let amount_unprocessed_redemption = T::Investment::redemption(who, investment_id)?; + // Amount needs to be denominated in foreign currency as it will be swapped into + // foreign currency such that the swap order amount is in the incoming currency + let amount_collected_foreign_denominated = T::CurrencyConverter::stable_to_stable( + foreign_payout_currency, + pool_currency, + collected.amount_collected, + )?; let post_state = pre_state .transition(RedeemTransition::CollectRedemption( amount_unprocessed_redemption, SwapOf:: { - amount: collected.amount_collected, + amount: amount_collected_foreign_denominated, currency_in: foreign_payout_currency, currency_out: pool_currency, }, diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 57a9f558da..40251d2fd5 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -56,8 +56,9 @@ impl InvestStateConfig for T { )] #[scale_info(skip_type_params(T))] pub enum InvestState { - /// Placeholder state for initialization which will never be stored on - /// chain. + /// Default state for initialization which will never be actively put into + /// chain state, i.e. if this state is the result of applying transition(s), + /// then the corresponding `InvestmentState` will be cleared. NoState, /// The investment is waiting to be processed. InvestmentOngoing { invest_amount: T::Balance }, @@ -284,8 +285,9 @@ pub enum RedeemState< Currency: Clone + Copy + PartialEq + Debug, > { #[default] - /// Placeholder state for initialization which will never be stored on - /// chain. + /// Default state for initialization which will never be actively put into + /// chain state, i.e. if this state is the result of applying transition(s), + /// then the corresponding `RedemptionState` will be cleared. NoState, /// There is no pending redemption process at this point. The investment can /// be redeemed up to the invested amount (after fulfillment). diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 35e82c328f..e412bfe8f2 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -767,7 +767,7 @@ where // Assumption: NOOP if investment is not foreign T::CollectedInvestmentHook::notify_status_change( ForeignInvestmentInfo { - owner: who.clone(), + owner: who, id: investment_id, last_swap_reason: None, }, @@ -902,7 +902,7 @@ where // Assumption: NOOP if investment is not foreign T::CollectedRedemptionHook::notify_status_change( ForeignInvestmentInfo { - owner: who.clone(), + owner: who, id: investment_id, last_swap_reason: None, }, From a69338fd778364f9dfc85d8bac14a0ce286a7258 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 20:31:13 +0200 Subject: [PATCH 67/96] refactor: rm CollectableRedemption states --- pallets/foreign-investments/src/impls/mod.rs | 36 +- .../foreign-investments/src/impls/redeem.rs | 405 ++++++++---------- pallets/foreign-investments/src/types.rs | 54 --- 3 files changed, 178 insertions(+), 317 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index db0a41f14f..b12d87e822 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -475,20 +475,14 @@ impl Pallet { } RedeemState::InvestedAnd { inner, .. } | RedeemState::NotInvestedAnd { inner } => { match inner { - InnerRedeemState::Redeeming { .. } | - InnerRedeemState::RedeemingAndCollectableRedemption { .. } | - InnerRedeemState::CollectableRedemption => { + InnerRedeemState::Redeeming { .. } => { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), None)) }, InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } | InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | - InnerRedeemState::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | InnerRedeemState::ActiveSwapIntoForeignCurrency { swap, .. } | - InnerRedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - InnerRedeemState::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | - InnerRedeemState::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { + InnerRedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), Some(swap))) }, @@ -508,7 +502,8 @@ impl Pallet { TokenSwapReason::Redemption, )?; - // Dispatch transition event, post swap state has priority if it exists as it is the result of the latest update + // Dispatch transition event, post swap state has priority if it exists as it is + // the result of the latest update if let Some(redeem_state_post_swap) = maybe_new_state_prio { Self::deposit_redemption_event(who, investment_id, Some(redeem_state_post_swap)); } else { @@ -608,12 +603,7 @@ impl Pallet { // includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` match inner_redeem_state { InnerRedeemState::SwapIntoForeignDone { done_swap, .. } - | InnerRedeemState::RedeemingAndSwapIntoForeignDone { done_swap, .. } - | InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - done_swap, - .. - } - | InnerRedeemState::CollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => { + | InnerRedeemState::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { Self::notify_executed_collect_redeem( who, investment_id, @@ -643,22 +633,6 @@ impl Pallet { RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } - InnerRedeemState::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - redeem_amount, - .. - } => { - let new_state = - state.swap_inner_state(InnerRedeemState::RedeemingAndCollectableRedemption { - redeem_amount, - }); - RedemptionState::::insert(who, investment_id, new_state); - Ok(Some(new_state)) - } - InnerRedeemState::CollectableRedemptionAndSwapIntoForeignDone { .. } => { - let new_state = state.swap_inner_state(InnerRedeemState::CollectableRedemption); - RedemptionState::::insert(who, investment_id, new_state); - Ok(Some(new_state)) - } _ => Ok(None), } } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index ab12209ada..36a53b407d 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -22,16 +22,9 @@ use crate::types::{ InnerRedeemState, InnerRedeemState::{ ActiveSwapIntoForeignCurrency, ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - CollectableRedemption, CollectableRedemptionAndActiveSwapIntoForeignCurrency, - CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - CollectableRedemptionAndSwapIntoForeignDone, Redeeming, - RedeemingAndActiveSwapIntoForeignCurrency, + Redeeming, RedeemingAndActiveSwapIntoForeignCurrency, RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - RedeemingAndCollectableRedemption, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone, RedeemingAndSwapIntoForeignDone, - SwapIntoForeignDone, + RedeemingAndSwapIntoForeignDone, SwapIntoForeignDone, }, RedeemState, RedeemTransition, }; @@ -163,14 +156,12 @@ where /// * Else, it returns `None`. fn get_active_swap(&self) -> Option> { match *self { - Self::ActiveSwapIntoForeignCurrency { swap } | - Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } | - Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } | - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + Self::ActiveSwapIntoForeignCurrency { swap } + | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } + | Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } + | Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, .. + } => Some(swap), _ => None, } } @@ -178,14 +169,13 @@ where /// Returns the redeeming amount if existent. Else returns zero. fn get_redeeming_amount(&self) -> Balance { match *self { - Self::Redeeming { redeem_amount } | - Self::RedeemingAndCollectableRedemption { redeem_amount, .. } | - Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, .. } | - Self::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } | - Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount, .. } | - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, .. } => redeem_amount, + Self::Redeeming { redeem_amount } + | Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, .. } + | Self::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } + | Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount, + .. + } => redeem_amount, _ => Balance::zero(), } } @@ -202,55 +192,47 @@ where fn fulfill_active_swap_amount(&self, amount: Balance) -> Result { match self { Self::ActiveSwapIntoForeignCurrency { swap } => { - if amount == swap.amount{ + if amount == swap.amount { Ok(Self::SwapIntoForeignDone { done_swap: *swap }) } else { - Ok( - Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount: amount - } - ) + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount: amount, + }) } - }, + } Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { - Ok( - Self::SwapIntoForeignDone { - done_swap: Swap { - amount: done_amount, - ..*swap - } - } - ) + Ok(Self::SwapIntoForeignDone { + done_swap: Swap { + amount: done_amount, + ..*swap + }, + }) } else { - Ok( - Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount, - } - ) + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount.ensure_sub(amount)?, + ..*swap + }, + done_amount, + }) } - }, - Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { + } + Self::RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount, + swap, + } => { if amount == swap.amount { - Ok( - Self::RedeemingAndSwapIntoForeignDone { - done_swap: Swap { - amount, - ..*swap - }, - redeem_amount: *redeem_amount, - } - ) + Ok(Self::RedeemingAndSwapIntoForeignDone { + done_swap: Swap { amount, ..*swap }, + redeem_amount: *redeem_amount, + }) } else { Ok( Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { @@ -260,23 +242,25 @@ where }, done_amount: amount, redeem_amount: *redeem_amount, - } + }, ) } - }, - Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { + } + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount, + swap, + done_amount, + } => { let done_amount = done_amount.ensure_add(amount)?; if amount == swap.amount { - Ok( - Self::RedeemingAndSwapIntoForeignDone { - done_swap: Swap { - amount: done_amount, - ..*swap - }, - redeem_amount: *redeem_amount, - } - ) + Ok(Self::RedeemingAndSwapIntoForeignDone { + done_swap: Swap { + amount: done_amount, + ..*swap + }, + redeem_amount: *redeem_amount, + }) } else { Ok( Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { @@ -286,103 +270,13 @@ where }, done_amount, redeem_amount: *redeem_amount, - } - ) - } - }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { - if amount == swap.amount { - Ok( - Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - done_swap: *swap, - redeem_amount: *redeem_amount, - } - ) - } else { - Ok( - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount: amount, - redeem_amount: *redeem_amount, - } - ) - } - }, - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { - let done_amount = done_amount.ensure_add(amount)?; - - if amount == swap.amount { - Ok( - Self::RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - done_swap: Swap { - amount: done_amount, - ..*swap - }, - redeem_amount: *redeem_amount, - } - ) - } else { - Ok( - Self::RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount, - redeem_amount: *redeem_amount, - } - ) - } - }, - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { - if amount == swap.amount { - Ok( - Self::CollectableRedemptionAndSwapIntoForeignDone { - done_swap: *swap, - } - ) - } else { - Ok( - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount: amount, - } - ) - } - }, - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { - let done_amount = done_amount.ensure_add(amount)?; - - if amount == swap.amount { - Ok( - Self::CollectableRedemptionAndSwapIntoForeignDone { - done_swap: Swap { - amount: done_amount, - ..*swap - }, - } - ) - } else { - Ok( - Self::CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: swap.amount.ensure_sub(amount)?, - ..*swap - }, - done_amount, - } + }, ) } - }, + } _ => Err(DispatchError::Other( "Invalid inner redeem state when fulfilling active swap amount", - )) + )), } } @@ -390,13 +284,9 @@ where fn remove_redeem_amount(&self) -> Result { match *self { Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), - RedeemingAndCollectableRedemption { .. } => Ok(CollectableRedemption), RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(ActiveSwapIntoForeignCurrency { swap }), RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(SwapIntoForeignDone { done_swap }), RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap }), - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), // Throw for states without `Redeeming` _ => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), } @@ -417,21 +307,49 @@ where return Self::remove_redeem_amount(self); } match *self { - Redeeming { .. } => Ok(Redeeming { redeem_amount: amount }), - RedeemingAndCollectableRedemption { .. } => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), - RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount: amount, swap }), - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, .. } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { redeem_amount: amount, done_swap }), - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount: amount, swap, done_amount }), - CollectableRedemption => Ok(RedeemingAndCollectableRedemption { redeem_amount: amount }), - ActiveSwapIntoForeignCurrency { swap } => Ok(RedeemingAndActiveSwapIntoForeignCurrency { swap, redeem_amount: amount }), - ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, redeem_amount: amount }), - SwapIntoForeignDone { done_swap } => Ok(RedeemingAndSwapIntoForeignDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { swap, redeem_amount: amount }), - CollectableRedemptionAndSwapIntoForeignDone { done_swap } => Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap, redeem_amount: amount }), - CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, redeem_amount: amount }), + Redeeming { .. } => Ok(Redeeming { + redeem_amount: amount, + }), + RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { + Ok(RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount: amount, + swap, + }) + } + RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + Ok(RedeemingAndSwapIntoForeignDone { + redeem_amount: amount, + done_swap, + }) + } + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + .. + } => Ok( + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount: amount, + swap, + done_amount, + }, + ), + ActiveSwapIntoForeignCurrency { swap } => { + Ok(RedeemingAndActiveSwapIntoForeignCurrency { + swap, + redeem_amount: amount, + }) + } + ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok( + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + redeem_amount: amount, + }, + ), + SwapIntoForeignDone { done_swap } => Ok(RedeemingAndSwapIntoForeignDone { + done_swap, + redeem_amount: amount, + }), } } @@ -472,65 +390,88 @@ where match *self { ActiveSwapIntoForeignCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) + Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount - amount, + ..swap + }, + done_amount: amount, + }) } else { Ok(SwapIntoForeignDone { done_swap: swap }) } - }, + } ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) - } else { - Ok(SwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap } }) - } - }, - RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { - if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) - } else { - Ok(RedeemingAndSwapIntoForeignDone { done_swap: swap, redeem_amount }) - } - }, - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { - let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) - } else { - Ok(RedeemingAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) - } - }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { redeem_amount, swap } => { - if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount, redeem_amount }) - } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: swap, redeem_amount }) - } - }, - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount } => { - let done_amount = done_amount.ensure_add(amount)?; - if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount, redeem_amount }) + Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount - amount, + ..swap + }, + done_amount, + }) } else { - Ok(RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap }, redeem_amount }) + Ok(SwapIntoForeignDone { + done_swap: Swap { + amount: done_amount, + ..swap + }, + }) } - }, - CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap } => { + } + RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount, + swap, + } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount: amount }) + Ok( + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount - amount, + ..swap + }, + done_amount: amount, + redeem_amount, + }, + ) } else { - Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap: swap }) + Ok(RedeemingAndSwapIntoForeignDone { + done_swap: swap, + redeem_amount, + }) } - }, - CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { + } + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount, + swap, + done_amount, + } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap }, done_amount }) + Ok( + RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: swap.amount - amount, + ..swap + }, + done_amount, + redeem_amount, + }, + ) } else { - Ok(CollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap } }) + Ok(RedeemingAndSwapIntoForeignDone { + done_swap: Swap { + amount: done_amount, + ..swap + }, + redeem_amount, + }) } - }, - _ => Err(DispatchError::Other("Invalid inner redeem state when transitioning fulfilled swap order")), + } + _ => Err(DispatchError::Other( + "Invalid inner redeem state when transitioning fulfilled swap order", + )), } } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 40251d2fd5..2543252d54 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -316,12 +316,6 @@ pub enum InnerRedeemState< > { /// The redemption is pending until it is processed during epoch execution. Redeeming { redeem_amount: Balance }, - /// The redemption was fully processed and must be collected before it can - /// be transferred back. - CollectableRedemption, - /// The redemption was partially processed and is split into a pending - /// redemption and a collectable amount. - RedeemingAndCollectableRedemption { redeem_amount: Balance }, /// The redemption was fully processed and collected and is currently /// swapping into the foreign currency. ActiveSwapIntoForeignCurrency { swap: Swap }, @@ -366,54 +360,6 @@ pub enum InnerRedeemState< swap: Swap, done_amount: Balance, }, - /// The redemption is split into three parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The remainder is swapping back into the foreign currency as a result - /// of processing and collecting beforehand. - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrency { - redeem_amount: Balance, - swap: Swap, - }, - /// The redemption is split into three parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The remainder was successfully swapped back into the foreign currency - /// as a result of processing and collecting beforehand. - RedeemingAndCollectableRedemptionAndSwapIntoForeignDone { - redeem_amount: Balance, - done_swap: Swap, - }, - /// The redemption is split into four parts: - /// * One part is waiting to be processed as redemption. - /// * The second is waiting to be collected. - /// * The third part is swapping back into the foreign currency as a result - /// of processing and collecting beforehand - /// * The remainder was already swapped back. - RedeemingAndCollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - redeem_amount: Balance, - swap: Swap, - done_amount: Balance, - }, - /// The redemption is split into two parts: - /// * One part is waiting to be collected. - /// * The remainder is swapping back into the foreign currency as a result - /// of processing and collecting beforehand. - CollectableRedemptionAndActiveSwapIntoForeignCurrency { swap: Swap }, - /// The redemption is split into two parts: - /// * One part is waiting to be collected. - /// * The remainder was successfully swapped back into the foreign currency - /// as a result of processing and collecting beforehand. - CollectableRedemptionAndSwapIntoForeignDone { done_swap: Swap }, - /// The redemption is split into three parts: - /// * One part is waiting to be collected. - /// * The second is swapping back into the foreign currency as a result of - /// processing and collecting beforehand - /// * The remainder was already swapped back. - CollectableRedemptionAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: Swap, - done_amount: Balance, - }, } /// Reflects all state transitions of a `RedeemState` which can be From ac55c51ed97f6a8ec919b0a8e4cbd96f031f9e8a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 20:31:30 +0200 Subject: [PATCH 68/96] fix: clippy --- pallets/foreign-investments/src/types.rs | 40 ++++++++++++------------ runtime/common/src/lib.rs | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 2543252d54..10e5106846 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -171,38 +171,38 @@ where match self { Self::NoState => Self::NoState, Self::InvestmentOngoing { invest_amount } => Self::InvestmentOngoing { - invest_amount: invest_amount.clone(), + invest_amount: *invest_amount, }, Self::ActiveSwapIntoPoolCurrency { swap } => { - Self::ActiveSwapIntoPoolCurrency { swap: swap.clone() } + Self::ActiveSwapIntoPoolCurrency { swap: *swap } } Self::ActiveSwapIntoForeignCurrency { swap } => { - Self::ActiveSwapIntoForeignCurrency { swap: swap.clone() } + Self::ActiveSwapIntoForeignCurrency { swap: *swap } } Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, invest_amount, } => Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: swap.clone(), - invest_amount: invest_amount.clone(), + swap: *swap, + invest_amount: *invest_amount, }, Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, invest_amount, } => Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap: swap.clone(), - invest_amount: invest_amount.clone(), + swap: *swap, + invest_amount: *invest_amount, }, Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, done_amount } => { Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { - swap: swap.clone(), - done_amount: done_amount.clone(), + swap: *swap, + done_amount: *done_amount, } } Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap: swap.clone(), - done_amount: done_amount.clone(), + swap: *swap, + done_amount: *done_amount, } } Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { @@ -210,28 +210,28 @@ where done_amount, invest_amount, } => Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap: swap.clone(), - done_amount: done_amount.clone(), - invest_amount: invest_amount.clone(), + swap: *swap, + done_amount: *done_amount, + invest_amount: *invest_amount, }, Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, done_amount, invest_amount, } => Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { - swap: swap.clone(), - done_amount: done_amount.clone(), - invest_amount: invest_amount.clone(), + swap: *swap, + done_amount: *done_amount, + invest_amount: *invest_amount, }, Self::SwapIntoForeignDone { done_swap } => Self::SwapIntoForeignDone { - done_swap: done_swap.clone(), + done_swap: *done_swap, }, Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap, invest_amount, } => Self::SwapIntoForeignDoneAndInvestmentOngoing { - done_swap: done_swap.clone(), - invest_amount: invest_amount.clone(), + done_swap: *done_swap, + invest_amount: *invest_amount, }, } } diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index fa370bdc83..33e26ada59 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -543,7 +543,7 @@ pub mod foreign_investments { to_metadata.decimals, StableToStableRate::get().ensure_mul_int(amount_out)?, ) - .map_err(|e| DispatchError::from(e)) + .map_err(DispatchError::from) } _ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)), } From d46a36378796053e5c6adc4694ad4dc7a5ef3605 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 29 Aug 2023 20:37:58 +0200 Subject: [PATCH 69/96] fix: increment redeeming amount --- pallets/foreign-investments/src/impls/redeem.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 36a53b407d..4df0b0b494 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -671,14 +671,15 @@ where invest_amount, inner, } => { + let redeeming_amount = self.get_redeeming_amount().ensure_add(amount)?; if &amount == invest_amount { Ok(Self::NotInvestedAnd { - inner: inner.set_redeem_amount(amount)?, + inner: inner.set_redeem_amount(redeeming_amount)?, }) } else { Ok(Self::InvestedAnd { invest_amount: invest_amount.ensure_sub(amount)?, - inner: inner.set_redeem_amount(amount)?, + inner: inner.set_redeem_amount(redeeming_amount)?, }) } } From 653e4b89538740743a3b929ced349aec3ee673fb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 30 Aug 2023 17:07:46 +0200 Subject: [PATCH 70/96] wip: complex collect flows --- .../liquidity_pools/foreign_investments.rs | 1894 ++++++++++------- 1 file changed, 1141 insertions(+), 753 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 110955b94b..fb61a9fa78 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -24,13 +24,13 @@ use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId, CFG}; use cfg_traits::{ - investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, + investments::{Investment, OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::InboundQueue, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, fixed_point::Rate, - investments::{InvestCollection, InvestmentAccount, RedeemCollection}, + investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection, Swap}, orders::FulfillmentWithPrice, permissions::{PermissionScope, PoolRole, Role, UNION}, pools::TrancheMetadata, @@ -48,12 +48,15 @@ use frame_support::{ traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, }; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; -use pallet_foreign_investments::types::{InnerRedeemState, InvestState, RedeemState}; +use pallet_foreign_investments::{ + types::{InnerRedeemState, InvestState, RedeemState}, + CollectedRedemption, RedemptionState, +}; use pallet_investments::CollectOutcome; use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, - BoundedVec, DispatchError, Perquintill, SaturatedConversion, WeakBoundedVec, + BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, WeakBoundedVec, }; use xcm_emulator::TestExt; @@ -81,416 +84,417 @@ use crate::{ }; mod same_currencies { + use pallet_foreign_investments::{CollectedInvestment, InvestmentState}; + use super::*; -} -#[test] -fn inbound_increase_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + #[test] + fn increase_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, amount, investor, currency_id); + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor, currency_id); - // Verify the order was updated to the amount - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - amount - ); - }); -} + // Verify the order was updated to the amount + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + amount + ); + }); + } -#[test] -fn inbound_decrease_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount: u128 = 100_000_000; - let decrease_amount = invest_amount / 3; - let final_amount = invest_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); - - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; + #[test] + fn decrease_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let decrease_amount = invest_amount / 3; + let final_amount = invest_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - enable_liquidity_pool_transferability(currency_id); + enable_liquidity_pool_transferability(currency_id); - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - final_amount - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: decrease_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); -} + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + final_amount + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: decrease_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); + } -#[test] -fn inbound_cancel_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + #[test] + fn cancel_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); - // Verify investment account holds funds before cancelling - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - invest_amount - ); + // Verify investment account holds funds before cancelling + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + invest_amount + ); - // Mock incoming cancel message - let msg = LiquidityPoolMessage::CancelInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Mock incoming cancel message + let msg = LiquidityPoolMessage::CancelInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; - // Expect failure if transferability is disabled since this is required for - // preparing the `ExecutedDecreaseInvest` message. - assert_noop!( + // Expect failure if transferability is disabled since this is required for + // preparing the `ExecutedDecreaseInvest` message. + assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), pallet_liquidity_pools::Error::::AssetNotLiquidityPoolsTransferable ); - enable_liquidity_pool_transferability(currency_id); + enable_liquidity_pool_transferability(currency_id); - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - // Foreign InvestmentState should be cleared - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(&investor, default_investment_id())); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + // Foreign InvestmentState should be cleared + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(&investor, default_investment_id())); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { investor: investor.clone(), investment_id: default_investment_id(), } .into() - })); + })); - // Verify investment was entirely drained from investment account - assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), - 0 - ); - // Since the investment was done in the pool currency, the decrement happens - // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount: invest_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - }); -} + // Verify investment was entirely drained from investment account + assert_eq!( + OrmlTokens::free_balance(currency_id, &default_investment_account()), + 0 + ); + // Since the investment was done in the pool currency, the decrement happens + // synchronously and thus it must be burned from investor's holdings + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: invest_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); + } -#[test] -fn inbound_collect_invest_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - let investment_currency_id: CurrencyId = default_investment_id().into(); - - // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); - let events_before_collect = System::events(); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::InvestCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_invest_orders(default_investment_id())); - - // Tranche tokens will be minted upon fulfillment - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); + #[test] + fn collect_invest_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + let investment_currency_id: CurrencyId = default_investment_id().into(); + + // Set permissions and execute initial investment + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::InvestCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_invest_orders(default_investment_id())); + + // Tranche tokens will be minted upon fulfillment + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); - // Verify investment was transferred to the domain locator - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - amount - ); + // Verify investment was transferred to the domain locator + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + amount + ); - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { investment_id: default_investment_id(), who: investor.clone(), } .into() - })); + })); - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0, - } - .into() - })); + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); - // Foreign CollectedInvestment should be killed - assert!(!pallet_foreign_investments::CollectedInvestment::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); + // Foreign CollectedInvestment should be killed + assert!(!pallet_foreign_investments::CollectedInvestment::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); - // Foreign InvestmentState should be killed - assert!(!pallet_foreign_investments::InvestmentState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); + // Foreign InvestmentState should be killed + assert!(!pallet_foreign_investments::InvestmentState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); - // Clearing of foreign InvestState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event + // Clearing of foreign InvestState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentCleared { investor: investor.clone(), investment_id: default_investment_id(), } .into() - })); - }); -} + })); + }); + } -#[test] -fn inbound_increase_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; + #[test] + fn increase_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, amount, investor, currency_id); + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, amount, investor, currency_id); - // Verify amount was noted in the corresponding order - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - amount - ); + // Verify amount was noted in the corresponding order + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + amount + ); - // increase again, state should be SwapIntoForeignDone - }); -} + // increase again, state should be SwapIntoForeignDone + }); + } -#[test] -fn inbound_decrease_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount = 100_000_000; - let decrease_amount = redeem_amount / 3; - let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); + #[test] + fn decrease_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let decrease_amount = redeem_amount / 3; + let final_amount = redeem_amount - decrease_amount; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - final_amount - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - decrease_amount - ); + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); - // Foreign RedemptionState should be updated - assert!(System::events().iter().any(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + final_amount + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + decrease_amount + ); + + // Foreign RedemptionState should be updated + assert!(System::events().iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), investment_id: default_investment_id(), state: RedeemState::InvestedAnd { @@ -501,456 +505,840 @@ fn inbound_decrease_redeem_order() { } } .into() - })); + })); - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - final_amount - ); - }); -} + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + final_amount + ); + }); + } -#[test] -fn inbound_cancel_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - - // Verify the corresponding redemption order id is 0 - assert_eq!( - pallet_investments::Pallet::::invest_order_id(investment_id( - pool_id, - default_tranche_id(pool_id) - )), - 0 - ); + #[test] + fn cancel_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::CancelRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Set permissions and execute initial redemption + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); - // Verify investment was decreased into investment account - assert_eq!( - OrmlTokens::free_balance( - default_investment_id().into(), - &default_investment_account(), - ), - 0 - ); - // Tokens should have been transferred from investor's wallet to domain's - // sovereign account - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), - 0 - ); - assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), - redeem_amount - ); + // Verify the corresponding redemption order id is 0 + assert_eq!( + pallet_investments::Pallet::::invest_order_id(investment_id( + pool_id, + default_tranche_id(pool_id) + )), + 0 + ); - // Foreign RedemptionState should be updated - assert!(System::events().iter().any(|e| { - e.event + // Mock incoming decrease message + let msg = LiquidityPoolMessage::CancelRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + // Verify investment was decreased into investment account + assert_eq!( + OrmlTokens::free_balance( + default_investment_id().into(), + &default_investment_account(), + ), + 0 + ); + // Tokens should have been transferred from investor's wallet to domain's + // sovereign account + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &investor), + 0 + ); + assert_eq!( + OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + redeem_amount + ); + + // Foreign RedemptionState should be updated + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), investment_id: default_investment_id(), state: RedeemState::Invested { invest_amount: redeem_amount }, } .into() - })); + })); - // Order should have been updated - assert!(System::events().iter().any(|e| e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: 0 - } - .into())); - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - 0 - ); - }); -} + // Order should have been updated + assert!(System::events().iter().any(|e| e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0 + } + .into())); + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + }); + } -#[test] -fn inbound_collect_redeem_order() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let pool_account = - pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); - - // Create new pool - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - - // Set permissions and execute initial investment - do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); - let events_before_collect = System::events(); - - // Fund the pool account with sufficient pool currency, else redemption cannot - // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - - // Process and fulfill order - // NOTE: Without this step, the order id is not cleared and - // `Event::RedeemCollectedForNonClearedOrderId` be dispatched - assert_ok!(Investments::process_redeem_orders(default_investment_id())); - assert_ok!(Investments::redeem_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); + #[test] + fn fully_collect_redeem_order() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + + // Create new pool + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + + // Set permissions and execute initial investment + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + let events_before_collect = System::events(); + + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + + // Process and fulfill order + // NOTE: Without this step, the order id is not cleared and + // `Event::RedeemCollectedForNonClearedOrderId` be dispatched + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); - // Enable liquidity pool transferability - enable_liquidity_pool_transferability(currency_id); + // Enable liquidity pool transferability + enable_liquidity_pool_transferability(currency_id); - // Mock collection message msg - let msg = LiquidityPoolMessage::CollectRedeem { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; + // Mock collection message msg + let msg = LiquidityPoolMessage::CollectRedeem { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - // Remove events before collect execution - let events_since_collect: Vec<_> = System::events() - .into_iter() - .filter(|e| !events_before_collect.contains(e)) - .collect(); + // Remove events before collect execution + let events_since_collect: Vec<_> = System::events() + .into_iter() + .filter(|e| !events_before_collect.contains(e)) + .collect(); - // Verify collected redemption was burned from investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); - assert!(System::events().iter().any(|e| e.event - == orml_tokens::Event::::Withdrawn { - currency_id, - who: investor.clone(), - amount - } - .into())); + // Verify collected redemption was burned from investor + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount + } + .into())); - // Order should have been cleared by fulfilling redemption - assert_eq!( - pallet_investments::Pallet::::acc_active_redeem_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert!(!events_since_collect.iter().any(|e| { - e.event + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert!(!events_since_collect.iter().any(|e| { + e.event == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { investment_id: default_investment_id(), who: investor.clone(), } .into() - })); + })); - // Order should not have been updated since everything is collected - assert!(!events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, + // Order should not have been updated since everything is collected + assert!(!events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: 0, + } + .into() + })); + + // Order should have been fully collected + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: amount, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Foreign CollectedRedemptionTrancheTokens should be killed + assert!(!pallet_foreign_investments::CollectedRedemption::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id(),)); + + // Foreign RedemptionState should be killed + assert!(!pallet_foreign_investments::RedemptionState::< + DevelopmentRuntime, + >::contains_key(investor.clone(), default_investment_id())); + + // Clearing of foreign RedeemState should be dispatched + assert!(events_since_collect.iter().any(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignRedemptionCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + })); + }); + } + + #[test] + fn partially_collect_redemption_for_through_investments() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption(pool_id, redeem_amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Fund the pool account with sufficient pool currency, else redemption cannot + // swap tranche tokens against pool currency + assert_ok!(OrmlTokens::mint_into( + currency_id, + &pool_account, + redeem_amount + )); + assert!(!Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + + // Process 50% of redemption at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(50), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + + // Pre collect assertions + assert!(Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + assert!(CollectedRedemption::::contains_key( + &investor, + default_investment_id() + )); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { redeem_amount } + } + ); + + // Collecting through investments should denote amounts and transition + // state + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: redeem_amount / 8, + remaining_investment_redeem: redeem_amount / 2, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + assert!(!Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + // Since foreign currency is pool currency, the swap is immediately fulfilled + // and ExecutedCollectRedeem dispatched + assert!(!CollectedRedemption::::contains_key( + &investor, + default_investment_id() + ),); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: redeem_amount / 2, + } + } + ); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, who: investor.clone(), - amount: 0, + amount: redeem_amount / 8 } - .into() - })); + .into())); - // Order should have been fully collected - assert!(events_since_collect.iter().any(|e| { - e.event - == pallet_investments::Event::::RedeemOrdersCollected { + // Process rest of redemption at 50% rate + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::checked_from_rational(1, 2).unwrap(), + } + )); + // Order should have been cleared by fulfilling redemption + assert_eq!( + pallet_investments::Pallet::::acc_active_redeem_order( + default_investment_id(), + ) + .amount, + 0 + ); + + // Collect remainder through Investments + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); + assert!(!Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + assert!(!CollectedRedemption::::contains_key( + &investor, + default_investment_id() + )); + assert!(!RedemptionState::::contains_key( + &investor, + default_investment_id() + )); + assert!(!System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemCollectedForNonClearedOrderId { investment_id: default_investment_id(), - processed_orders: vec![0], who: investor.clone(), - collection: RedeemCollection:: { - payout_investment_redeem: amount, - remaining_investment_redeem: 0, - }, - outcome: CollectOutcome::FullyCollected, } .into() - })); - - // Foreign CollectedRedemptionTrancheTokens should be killed - assert!(!pallet_foreign_investments::CollectedRedemption::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id(),)); - - // Foreign RedemptionState should be killed - assert!(!pallet_foreign_investments::RedemptionState::< - DevelopmentRuntime, - >::contains_key(investor.clone(), default_investment_id())); - - // Clearing of foreign RedeemState should be dispatched - assert!(events_since_collect.iter().any(|e| { - e.event + })); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::RedeemOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![1], + who: investor.clone(), + collection: RedeemCollection:: { + payout_investment_redeem: redeem_amount / 4, + remaining_investment_redeem: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + // Verify collected redemption was burned from investor + assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert!(System::events().iter().any(|e| e.event + == orml_tokens::Event::::Withdrawn { + currency_id, + who: investor.clone(), + amount: redeem_amount / 4 + } + .into())); + // Clearing of foreign RedeemState should have been dispatched exactly once + assert_eq!( + System::events() + .iter() + .filter(|e| { + e.event == pallet_foreign_investments::Event::::ForeignRedemptionCleared { investor: investor.clone(), investment_id: default_investment_id(), } .into() - })); - }); -} + }) + .count(), + 1 + ); + }); + } -mod should_fail { - use pallet_foreign_investments::errors::{InvestError, RedeemError}; + #[test] + fn partially_collect_investment_for_through_investments() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + let investment_currency_id: CurrencyId = default_investment_id().into(); + + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); - use super::*; + // Process 50% of investment at 400% rate, i.e. 1 tranche token = 4 pool + // currency + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(50), + price: Rate::checked_from_rational(4, 1).unwrap(), + } + )); + // assert_eq!( + // OrmlTokens::total_issuance(investment_currency_id), + // invest_amount / 8 + // invest_amount + // ); + + // Pre collect assertions + assert!(Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + assert!(!CollectedInvestment::::contains_key( + &investor, + default_investment_id() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::::InvestmentOngoing { invest_amount } + ); - mod decrease_should_underflow { - use super::*; + // Collecting through Investments should denote amounts and transition + // state + assert_ok!(Investments::collect_investments_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); - #[test] - fn invest_decrease_underflow() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount: u128 = 100_000_000; - let decrease_amount = invest_amount + 1; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment( - pool_id, - invest_amount, - investor.clone(), - currency_id, - ); - enable_liquidity_pool_transferability(currency_id); + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + // The collected amount is only transferred to the user if they send a + // `CollectInvest` message + assert_eq!( + CollectedInvestment::::get(&investor, default_investment_id()), + CollectedAmount { + amount_collected: invest_amount / 8, + amount_payment: invest_amount / 4, + } + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::::InvestmentOngoing { + invest_amount: invest_amount / 2 + } + ); + // Tokens should be still owned by investor + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &investor), + invest_amount / 8 + ); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + 0 + ); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: invest_amount / 8, + remaining_investment_invest: invest_amount / 2, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::Decrease - ) - ); - }); - } + // Process rest of investment at 50% rate + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::checked_from_rational(1, 2).unwrap(), + } + )); + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert_eq!( + OrmlTokens::total_issuance(investment_currency_id), + invest_amount / 4 + invest_amount / 8 + ); - #[test] - fn redeem_decrease_underflow() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let redeem_amount: u128 = 100_000_000; - let decrease_amount = redeem_amount + 1; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_redemption( - pool_id, - redeem_amount, - investor.clone(), - currency_id, - ); + // Collect remainder through Investments + assert_ok!(Investments::collect_investments_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + assert_eq!( + CollectedInvestment::::get(&investor, default_investment_id()), + CollectedAmount { + amount_collected: invest_amount / 4 + invest_amount / 8, + amount_payment: invest_amount, + } + ); + assert!(!InvestmentState::::contains_key( + &investor, + default_investment_id() + )); + // Tokens should still be investor's walled + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &investor), + invest_amount / 4 + invest_amount / 8 + ); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + 0 + ); + assert!(!System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![1], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: invest_amount / 4, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + // Clearing of foreign InvestState should have been dispatched exactly once + assert_eq!( + System::events() + .iter() + .filter(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + }) + .count(), + 1 + ); - // Mock incoming decrease message - let msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: decrease_amount, - }; - - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::Decrease - ) - ); - }); - } + // User collects + }); } - mod should_throw_requires_collect { + mod should_fail { + use pallet_foreign_investments::errors::{InvestError, RedeemError}; + use super::*; - #[test] - fn invest_requires_collect() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); - enable_liquidity_pool_transferability(currency_id); - - // Prepare collection - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - assert_ok!(Investments::process_invest_orders(default_investment_id())); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::CollectRequired - ) - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), - pallet_foreign_investments::Error::::InvestError( - InvestError::CollectRequired - ) - ); - }); + mod decrease_should_underflow { + use super::*; + + #[test] + fn invest_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount: u128 = 100_000_000; + let decrease_amount = invest_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment( + pool_id, + invest_amount, + investor.clone(), + currency_id, + ); + enable_liquidity_pool_transferability(currency_id); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::Decrease + ) + ); + }); + } + + #[test] + fn redeem_decrease_underflow() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let redeem_amount: u128 = 100_000_000; + let decrease_amount = redeem_amount + 1; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption( + pool_id, + redeem_amount, + investor.clone(), + currency_id, + ); + + // Mock incoming decrease message + let msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: decrease_amount, + }; + + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::Decrease + ) + ); + }); + } } - #[test] - fn redeem_requires_collect() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); - let currency_id: CurrencyId = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); - enable_liquidity_pool_transferability(currency_id); - - // Mint more into DomainLocator required for subsequent invest attempt - assert_ok!(OrmlTokens::mint_into( - default_investment_id().into(), - &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), - 1, - )); - - // Prepare collection - let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } - .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); - assert_ok!(Investments::process_redeem_orders(default_investment_id())); - assert_ok!(Investments::redeem_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::one(), - } - )); + mod should_throw_requires_collect { + use super::*; + #[test] + fn invest_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::InvestError( + InvestError::CollectRequired + ) + ); + }); + } - // Should fail to increase - let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::CollectRequired - ) - ); - - // Should fail to decrease - let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount: 1, - }; - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), - pallet_foreign_investments::Error::::RedeemError( - RedeemError::CollectRequired - ) - ); - }); + #[test] + fn redeem_requires_collect() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let amount: u128 = 100_000_000; + let investor: AccountId = BOB.into(); + let currency_id: CurrencyId = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + + // Mint more into DomainLocator required for subsequent invest attempt + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + 1, + )); + + // Prepare collection + let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } + .into_account_truncating(); + assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::one(), + } + )); + + // Should fail to increase + let increase_msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, increase_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + + // Should fail to decrease + let decrease_msg = LiquidityPoolMessage::DecreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount: 1, + }; + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg), + pallet_foreign_investments::Error::::RedeemError( + RedeemError::CollectRequired + ) + ); + }); + } } } } From 578103e64e5567edef8fed7bc3fa6dcb2c18c84c Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 31 Aug 2023 19:48:48 +0200 Subject: [PATCH 71/96] fix: inc invest for ActiveSwapIntoForeignCurrency --- pallets/foreign-investments/src/impls/invest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index e9f637a643..dc8106b776 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -252,7 +252,7 @@ where ..swap }, done_amount: foreign_swap.amount, - invest_amount: swap.amount, + invest_amount: foreign_amount_pool_denominated, }, ) } From ff07d88207dcbbf46def8cea4f2cd75d1112a585 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 31 Aug 2023 20:16:25 +0200 Subject: [PATCH 72/96] fix: domain based evm account conversion --- pallets/liquidity-pools/src/lib.rs | 35 ++++++++++++++---------- runtime/altair/src/lib.rs | 3 +- runtime/common/src/account_conversion.rs | 16 ++++++++++- runtime/development/src/lib.rs | 3 +- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index fcb55c46a4..e23173deb7 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -252,7 +252,10 @@ pub mod pallet { + CurrencyInspect>; /// The converter from a DomainAddress to a Substrate AccountId. - type AccountConverter: Convert; + type DomainAddressToAccountId: Convert; + + /// The converter from a Domain 32 byte array to Substrate AccountId. + type DomainAccountToAccountId: Convert<(Domain, [u8; 32]), Self::AccountId>; /// The type for processing outgoing messages. type OutboundQueue: OutboundQueue< @@ -517,7 +520,7 @@ pub mod pallet { ensure!( T::Permission::has( PermissionScope::Pool(pool_id), - T::AccountConverter::convert(domain_address.clone()), + T::DomainAddressToAccountId::convert(domain_address.clone()), Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)) ), Error::::InvestorDomainAddressNotAMember @@ -558,7 +561,7 @@ pub mod pallet { ensure!( T::Permission::has( PermissionScope::Pool(pool_id), - T::AccountConverter::convert(domain_address.clone()), + T::DomainAddressToAccountId::convert(domain_address.clone()), Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, Self::now())) ), Error::::UnauthorizedTransfer @@ -884,7 +887,11 @@ pub mod pallet { receiver, amount, .. - } => Self::handle_transfer(currency.into(), receiver.into(), amount), + } => Self::handle_transfer( + currency.into(), + T::DomainAccountToAccountId::convert((sender.domain(), receiver)), + amount, + ), Message::TransferTrancheTokens { pool_id, tranche_id, @@ -894,8 +901,8 @@ pub mod pallet { } => Self::handle_tranche_tokens_transfer( pool_id, tranche_id, - sender, - receiver.into(), + sender.clone(), + T::DomainAccountToAccountId::convert((sender.domain(), receiver)), amount, ), Message::IncreaseInvestOrder { @@ -907,7 +914,7 @@ pub mod pallet { } => Self::handle_increase_invest_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), amount, ), @@ -920,7 +927,7 @@ pub mod pallet { } => Self::handle_decrease_invest_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), amount, ), @@ -933,7 +940,7 @@ pub mod pallet { } => Self::handle_increase_redeem_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), amount, currency.into(), sender, @@ -947,7 +954,7 @@ pub mod pallet { } => Self::handle_decrease_redeem_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), amount, currency.into(), sender, @@ -960,7 +967,7 @@ pub mod pallet { } => Self::handle_collect_investment( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), sender, ), @@ -972,7 +979,7 @@ pub mod pallet { } => Self::handle_collect_redemption( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), ), Message::CancelInvestOrder { @@ -983,7 +990,7 @@ pub mod pallet { } => Self::handle_cancel_invest_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), ), Message::CancelRedeemOrder { @@ -994,7 +1001,7 @@ pub mod pallet { } => Self::handle_cancel_redeem_order( pool_id, tranche_id, - investor.into(), + T::DomainAccountToAccountId::convert((sender.domain(), investor)), currency.into(), sender, ), diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index a959d6a4e7..b0c7220b68 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1415,11 +1415,12 @@ impl pallet_foreign_investments::Config for Runtime { } impl pallet_liquidity_pools::Config for Runtime { - type AccountConverter = AccountConverter; type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type CurrencyId = CurrencyId; + type DomainAccountToAccountId = AccountConverter; + type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; type OutboundQueue = LiquidityPoolsGateway; diff --git a/runtime/common/src/account_conversion.rs b/runtime/common/src/account_conversion.rs index 4a0ef9afc0..f5cfb4ca38 100644 --- a/runtime/common/src/account_conversion.rs +++ b/runtime/common/src/account_conversion.rs @@ -11,7 +11,7 @@ // GNU General Public License for more details. use cfg_primitives::AccountId; -use cfg_types::domain_address::DomainAddress; +use cfg_types::domain_address::{Domain, DomainAddress}; use pallet_evm::AddressMapping; use sp_core::{Get, H160}; use sp_runtime::traits::Convert; @@ -60,6 +60,20 @@ impl Convert for AccountConverter { } } +impl Convert<(Domain, [u8; 32]), AccountId> for AccountConverter { + fn convert((domain, account): (Domain, [u8; 32])) -> AccountId { + match domain { + Domain::Centrifuge => AccountId::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) + } + } + } +} + #[cfg(test)] mod tests { use hex_literal::hex; diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index a0c7c84c62..15ae0dc9fc 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1607,11 +1607,12 @@ parameter_types! { } impl pallet_liquidity_pools::Config for Runtime { - type AccountConverter = AccountConverter; type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; type CurrencyId = CurrencyId; + type DomainAccountToAccountId = AccountConverter; + type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; type OutboundQueue = LiquidityPoolsGateway; From f9094d97b94576e78989f35a6fabcce4abef489f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 1 Sep 2023 10:52:39 +0200 Subject: [PATCH 73/96] fix: rm domain account conversion for receiver --- pallets/liquidity-pools/src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index e23173deb7..c0f02c0498 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -887,11 +887,7 @@ pub mod pallet { receiver, amount, .. - } => Self::handle_transfer( - currency.into(), - T::DomainAccountToAccountId::convert((sender.domain(), receiver)), - amount, - ), + } => Self::handle_transfer(currency.into(), receiver.into(), amount), Message::TransferTrancheTokens { pool_id, tranche_id, @@ -902,7 +898,7 @@ pub mod pallet { pool_id, tranche_id, sender.clone(), - T::DomainAccountToAccountId::convert((sender.domain(), receiver)), + receiver.into(), amount, ), Message::IncreaseInvestOrder { From ebf4552464d787ab658c54d20ea43cf439754483 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 1 Sep 2023 10:53:06 +0200 Subject: [PATCH 74/96] tests: fix existing integration foreign inv --- .../liquidity_pools/foreign_investments.rs | 101 ++++++++++++------ 1 file changed, 69 insertions(+), 32 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index fb61a9fa78..286ff24a35 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -76,7 +76,7 @@ use crate::{ general_currency_index, investment_id, }, setup_pre_requirements, LiquidityPoolMessage, DEFAULT_DOMAIN_ADDRESS_MOONBEAM, - DEFAULT_POOL_ID, DEFAULT_VALIDITY, + DEFAULT_POOL_ID, DEFAULT_VALIDITY, DOMAIN_MOONBEAM, }, }, }, @@ -95,7 +95,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -125,7 +126,8 @@ mod same_currencies { let invest_amount: u128 = 100_000_000; let decrease_amount = invest_amount / 3; let final_amount = invest_amount - decrease_amount; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -195,7 +197,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -282,7 +285,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -408,7 +412,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -440,7 +445,8 @@ mod same_currencies { let redeem_amount = 100_000_000; let decrease_amount = redeem_amount / 3; let final_amount = redeem_amount - decrease_amount; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -533,7 +539,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -620,7 +627,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = @@ -753,7 +761,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = @@ -790,7 +799,7 @@ mod same_currencies { &investor, default_investment_id() )); - assert!(CollectedRedemption::::contains_key( + assert!(!CollectedRedemption::::contains_key( &investor, default_investment_id() )); @@ -940,7 +949,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -954,14 +964,14 @@ mod same_currencies { default_investment_id() )); - // Process 50% of investment at 400% rate, i.e. 1 tranche token = 4 pool - // currency + // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), FulfillmentWithPrice:: { of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(4, 1).unwrap(), + price: Rate::checked_from_rational(1, 4).unwrap(), } )); // assert_eq!( @@ -1001,8 +1011,8 @@ mod same_currencies { assert_eq!( CollectedInvestment::::get(&investor, default_investment_id()), CollectedAmount { - amount_collected: invest_amount / 8, - amount_payment: invest_amount / 4, + amount_collected: invest_amount / 2 * 4, + amount_payment: invest_amount / 2, } ); assert_eq!( @@ -1011,10 +1021,11 @@ mod same_currencies { invest_amount: invest_amount / 2 } ); - // Tokens should be still owned by investor + // Tranche Tokens should still be investor's wallet (i.e. not be collected to + // domain) assert_eq!( OrmlTokens::free_balance(investment_currency_id, &investor), - invest_amount / 8 + invest_amount * 2 ); assert_eq!( OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), @@ -1027,7 +1038,7 @@ mod same_currencies { processed_orders: vec![0], who: investor.clone(), collection: InvestCollection:: { - payout_investment_invest: invest_amount / 8, + payout_investment_invest: invest_amount * 2, remaining_investment_invest: invest_amount / 2, }, outcome: CollectOutcome::FullyCollected, @@ -1035,7 +1046,7 @@ mod same_currencies { .into() })); - // Process rest of investment at 50% rate + // Process rest of investment at 50% rate (1 pool currency = 2 tranche tokens) assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), @@ -1054,7 +1065,7 @@ mod same_currencies { ); assert_eq!( OrmlTokens::total_issuance(investment_currency_id), - invest_amount / 4 + invest_amount / 8 + invest_amount * 3 ); // Collect remainder through Investments @@ -1070,7 +1081,7 @@ mod same_currencies { assert_eq!( CollectedInvestment::::get(&investor, default_investment_id()), CollectedAmount { - amount_collected: invest_amount / 4 + invest_amount / 8, + amount_collected: invest_amount * 3, amount_payment: invest_amount, } ); @@ -1078,10 +1089,11 @@ mod same_currencies { &investor, default_investment_id() )); - // Tokens should still be investor's walled + // Tranche Tokens should still be investor's wallet (i.e. not be collected to + // domain) assert_eq!( OrmlTokens::free_balance(investment_currency_id, &investor), - invest_amount / 4 + invest_amount / 8 + invest_amount * 3 ); assert_eq!( OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), @@ -1102,7 +1114,7 @@ mod same_currencies { processed_orders: vec![1], who: investor.clone(), collection: InvestCollection:: { - payout_investment_invest: invest_amount / 4, + payout_investment_invest: invest_amount, remaining_investment_invest: 0, }, outcome: CollectOutcome::FullyCollected, @@ -1125,7 +1137,27 @@ mod same_currencies { 1 ); - // User collects + // User collects through foreign investments + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + assert!(!CollectedInvestment::::contains_key( + &investor, + default_investment_id() + )); + assert_eq!( + OrmlTokens::total_issuance(investment_currency_id), + invest_amount * 3 + ); + assert!(OrmlTokens::free_balance(investment_currency_id, &investor).is_zero()); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + invest_amount * 3 + ); }); } @@ -1145,7 +1177,8 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let invest_amount: u128 = 100_000_000; let decrease_amount = invest_amount + 1; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1183,7 +1216,8 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let redeem_amount: u128 = 100_000_000; let decrease_amount = redeem_amount + 1; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1222,7 +1256,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1281,7 +1316,8 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount: u128 = 100_000_000; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1364,7 +1400,8 @@ mod mismatching_currencies { Development::execute_with(|| { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; - let investor: AccountId = BOB.into(); + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; let pool_currency_decimals = currency_decimals::AUSD; From 04e787cb273b7cb3f8bcefb5e187d33d5a3a3210 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 1 Sep 2023 11:39:27 +0200 Subject: [PATCH 75/96] tests: extend checks for existing --- .../liquidity_pools/foreign_investments.rs | 187 ++++++++++++------ 1 file changed, 122 insertions(+), 65 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 286ff24a35..7c46af5010 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -26,6 +26,7 @@ use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, use cfg_traits::{ investments::{Investment, OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::InboundQueue, + PoolInspect, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, @@ -41,7 +42,7 @@ use cfg_types::{ }; use development_runtime::{ Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, OrmlTokens, - Permissions, Runtime as DevelopmentRuntime, RuntimeOrigin, System, + Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, System, }; use frame_support::{ assert_noop, assert_ok, @@ -50,7 +51,7 @@ use frame_support::{ use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use pallet_foreign_investments::{ types::{InnerRedeemState, InvestState, RedeemState}, - CollectedRedemption, RedemptionState, + CollectedRedemption, InvestmentState, RedemptionState, }; use pallet_investments::CollectOutcome; use runtime_common::account_conversion::AccountConverter; @@ -104,7 +105,7 @@ mod same_currencies { create_currency_pool(pool_id, currency_id, currency_decimals.into()); // Set permissions and execute initial investment - do_initial_increase_investment(pool_id, amount, investor, currency_id); + do_initial_increase_investment(pool_id, amount, investor.clone(), currency_id); // Verify the order was updated to the amount assert_eq!( @@ -114,6 +115,22 @@ mod same_currencies { .amount, amount ); + + // Increasing again should just bump invest_amount + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: amount * 2 + } + ); }); } @@ -421,7 +438,7 @@ mod same_currencies { create_currency_pool(pool_id, currency_id, currency_decimals.into()); // Set permissions and execute initial redemption - do_initial_increase_redemption(pool_id, amount, investor, currency_id); + do_initial_increase_redemption(pool_id, amount, investor.clone(), currency_id); // Verify amount was noted in the corresponding order assert_eq!( @@ -432,7 +449,28 @@ mod same_currencies { amount ); - // increase again, state should be SwapIntoForeignDone + // Increasing again should just bump redeeming amount + assert_ok!(OrmlTokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + amount + )); + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: amount * 2, + } + } + ); }); } @@ -991,7 +1029,7 @@ mod same_currencies { )); assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::::InvestmentOngoing { invest_amount } + InvestState::InvestmentOngoing { invest_amount } ); // Collecting through Investments should denote amounts and transition @@ -1017,7 +1055,7 @@ mod same_currencies { ); assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::::InvestmentOngoing { + InvestState::InvestmentOngoing { invest_amount: invest_amount / 2 } ); @@ -1490,21 +1528,21 @@ mod mismatching_currencies { // Entire swap amount into pool currency should be nullified assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::::InvestmentOngoing { + InvestState::InvestmentOngoing { invest_amount: invest_amount_pool_denominated } ); - // assert!(System::events().iter().any(|e| { - // e.event == - // pallet_foreign_investments::Event::::ForeignInvestmentUpdated - // { investor: investor.clone(), - // investment_id: default_investment_id(), - // state: InvestState::InvestmentOngoing { - // invest_amount: invest_amount_foreign_denominated - // }, - // } - // .into() - // })); + assert!(System::events().iter().any(|e| { + e.event == + pallet_foreign_investments::Event::::ForeignInvestmentUpdated + { investor: investor.clone(), + investment_id: default_investment_id(), + state: InvestState::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated + }, + } + .into() + })); // Decrease partial investing amount enable_liquidity_pool_transferability(foreign_currency); @@ -1520,64 +1558,53 @@ mod mismatching_currencies { decrease_msg_partial_invest_amount.clone() )); // Decreased amount should be taken from investing amount + let expected_state = InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: Swap { + amount: invest_amount_foreign_denominated / 2, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + invest_amount: invest_amount_pool_denominated / 2, + }; assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap: Swap { - amount: invest_amount_foreign_denominated / 2, - currency_in: foreign_currency, - currency_out: pool_currency, - }, - invest_amount: invest_amount_pool_denominated / 2 - } + expected_state.clone() ); - // assert!(System::events().iter().any(|e| { - // e.event == - // pallet_foreign_investments::Event::::ForeignInvestmentUpdated - // { investor: investor.clone(), - // investment_id: default_investment_id(), - // state: InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - // swap: Swap { - // amount: invest_amount_foreign_denominated / 2, - // currency_in: foreign_currency, - // currency_out: pool_currency, - // }, - // invest_amount: invest_amount_foreign_denominated / 2 - // }, - // } - // .into() - // })); + assert!(System::events().iter().any(|e| { + e.event == + pallet_foreign_investments::Event::::ForeignInvestmentUpdated + { investor: investor.clone(), + investment_id: default_investment_id(), + state: expected_state.clone() + } + .into() + })); /// Consume entire investing amount by sending same message assert_ok!(LiquidityPools::submit( DEFAULT_DOMAIN_ADDRESS_MOONBEAM, decrease_msg_partial_invest_amount.clone() )); + let expected_state = InvestState::ActiveSwapIntoForeignCurrency { + swap: Swap { + amount: invest_amount_foreign_denominated, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + }; assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::::ActiveSwapIntoForeignCurrency { - swap: Swap { - amount: invest_amount_foreign_denominated, - currency_in: foreign_currency, - currency_out: pool_currency, - }, - } + expected_state.clone() ); - // assert!(System::events().iter().any(|e| { - // e.event == - // pallet_foreign_investments::Event::::ForeignInvestmentUpdated - // { investor: investor.clone(), - // investment_id: default_investment_id(), - // state: InvestState::ActiveSwapIntoForeignCurrency { - // swap: Swap { - // amount: invest_amount_foreign_denominated, - // currency_in: foreign_currency, - // currency_out: pool_currency, - // } - // }, - // } - // .into() - // })); + assert!(System::events().iter().any(|e| { + e.event == + pallet_foreign_investments::Event::::ForeignInvestmentUpdated + { investor: investor.clone(), + investment_id: default_investment_id(), + state: expected_state.clone() + } + .into() + })); }); } @@ -1639,6 +1666,28 @@ mod setup { // Execute byte message assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + let pool_currency: CurrencyId = + PoolSystem::currency_for(pool_id).expect("Pool existence checked already"); + dbg!(pool_currency, currency_id); + if currency_id == pool_currency { + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: amount + } + ); + } else { + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrency { + swap: Swap { + currency_in: pool_currency, + currency_out: currency_id, + amount + } + } + ); + } // Verify investment was transferred into investment account assert_eq!( OrmlTokens::free_balance(currency_id, &default_investment_account()), @@ -1733,6 +1782,14 @@ mod setup { assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::NotInvestedAnd { + inner: InnerRedeemState::Redeeming { + redeem_amount: amount + } + } + ); // Verify redemption was transferred into investment account assert_eq!( OrmlTokens::free_balance( From 4674b2dac5bc763a7abe3ef7340156215329b451 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 4 Sep 2023 09:31:23 +0200 Subject: [PATCH 76/96] refactor: simplify redeem states --- pallets/foreign-investments/src/impls/mod.rs | 120 ++--- .../foreign-investments/src/impls/redeem.rs | 471 +++++------------- pallets/foreign-investments/src/lib.rs | 2 - pallets/foreign-investments/src/types.rs | 29 +- .../liquidity_pools/foreign_investments.rs | 41 +- 5 files changed, 196 insertions(+), 467 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index b12d87e822..7fb13843cb 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -28,10 +28,7 @@ use sp_runtime::{ use crate::{ errors::{InvestError, RedeemError}, - types::{ - InnerRedeemState, InvestState, InvestTransition, RedeemState, RedeemTransition, - TokenSwapReason, - }, + types::{InvestState, InvestTransition, RedeemState, RedeemTransition, TokenSwapReason}, CollectedInvestment, CollectedRedemption, Config, Error, Event, ForeignInvestmentInfo, ForeignInvestmentInfoOf, InvestmentState, Pallet, RedemptionPayoutCurrency, RedemptionState, SwapOf, TokenSwapOrderIds, @@ -145,8 +142,7 @@ impl ForeignInvestment for Pallet { Error::::RedeemError(RedeemError::CollectRequired) ); - let pre_state = - RedemptionState::::get(who, investment_id).increase_invested_amount(amount)?; + let pre_state = RedemptionState::::get(who, investment_id); let post_state = pre_state .transition(RedeemTransition::IncreaseRedeemOrder(amount)) .map_err(|e| { @@ -310,9 +306,9 @@ impl Pallet { /// `ForeignInvestmentCleared`. /// /// 5. If the token swap handling resulted in a new `RedeemState`, update - /// `RedemptionState` again. If the corresponding new `InnerRedeemState` - /// includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency`, - /// remove the `SwapIntoForeignDone` part or kill it. Additionally, emit + /// `RedemptionState` again. If the result includes `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency`, remove the + /// `SwapIntoForeignDone` part or kill it. Additionally, emit /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 6. Update the investment. This also includes setting it to zero. We @@ -438,9 +434,9 @@ impl Pallet { /// `RedemptionState` might require an update. /// /// 4. If the token swap handling resulted in a new `RedeemState`, update - /// `RedemptionState` again. If the corresponding new `InnerRedeemState` - /// includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency`, - /// remove the `SwapIntoForeignDone` part or kill it. Additionally, emit + /// `RedemptionState` again. If the result includes `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency`, remove the + /// `SwapIntoForeignDone` part or kill it. Additionally, emit /// `ForeignRedemptionUpdate` or `ForeignRedemptionCleared`. /// /// 5. If the token swap handling resulted in a new `InvestState`, @@ -451,7 +447,7 @@ impl Pallet { /// assume the impl of `::Investment` handles this case. /// /// NOTES: - /// * Must be called after transitionin g any `RedeemState` via + /// * Must be called after transitioning g any `RedeemState` via /// `transition` to update the chain storage. /// * When updating token swap orders, only `handle_swap_order` should /// be called. @@ -469,29 +465,26 @@ impl Pallet { RedemptionState::::remove(who, investment_id); Ok((Some(RedeemState::NoState), None)) } - RedeemState::Invested { .. } => { + RedeemState::Redeeming { .. } => { RedemptionState::::insert(who, investment_id, state); Ok((Some(state), None)) } - RedeemState::InvestedAnd { inner, .. } | RedeemState::NotInvestedAnd { inner } => { - match inner { - InnerRedeemState::Redeeming { .. } => { - RedemptionState::::insert(who, investment_id, state); - Ok((Some(state), None)) - }, - InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } | - InnerRedeemState::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } | - InnerRedeemState::ActiveSwapIntoForeignCurrency { swap, .. } | - InnerRedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { - RedemptionState::::insert(who, investment_id, state); - Ok((Some(state), Some(swap))) - }, - // Only states left include `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` such that we can notify collect - inner => { - let maybe_new_state = Self::apply_collect_redeem_transition(who, investment_id, state, inner)?; - Ok((maybe_new_state, None)) - } - } + RedeemState::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } + | RedeemState::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + .. + } + | RedeemState::ActiveSwapIntoForeignCurrency { swap, .. } + | RedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { + RedemptionState::::insert(who, investment_id, state); + Ok((Some(state), Some(swap))) + } + // Only states left include `SwapIntoForeignDone` without + // `ActiveSwapIntoForeignCurrency` such that we can notify collect + swap_done_state => { + let maybe_new_state = + Self::apply_collect_redeem_transition(who, investment_id, swap_done_state)?; + Ok((maybe_new_state, None)) } } .map(|(maybe_new_state, maybe_swap)| { @@ -574,8 +567,8 @@ impl Pallet { /// Terminates a redeem collection which required swapping into foreign /// currency. /// - /// Only acts upon inner redeem states which include `SwapIntoForeignDone` - /// without `ActiveSwapIntoForeignCurrency`. Other inner states are ignored. + /// Only acts upon redeem states which include `SwapIntoForeignDone` + /// without `ActiveSwapIntoForeignCurrency`. Other states are ignored. /// Either updates the corresponding `RedemptionState` or drops it entirely. /// /// Emits `notify_executed_collect_redeem`. @@ -592,7 +585,6 @@ impl Pallet { who: &T::AccountId, investment_id: T::InvestmentId, state: RedeemState, - inner_redeem_state: InnerRedeemState, ) -> Result>, DispatchError> { let CollectedAmount:: { amount_payment: amount_payment_tranche_tokens, @@ -601,9 +593,9 @@ impl Pallet { // Send notification and kill `CollectedRedemptionTrancheTokens` iff the state // includes `SwapIntoForeignDone` without `ActiveSwapIntoForeignCurrency` - match inner_redeem_state { - InnerRedeemState::SwapIntoForeignDone { done_swap, .. } - | InnerRedeemState::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + match state { + RedeemState::SwapIntoForeignDone { done_swap, .. } + | RedeemState::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { Self::notify_executed_collect_redeem( who, investment_id, @@ -622,14 +614,13 @@ impl Pallet { // Update state iff the state includes `SwapIntoForeignDone` without // `ActiveSwapIntoForeignCurrency` - match inner_redeem_state { - InnerRedeemState::SwapIntoForeignDone { .. } => { + match state { + RedeemState::SwapIntoForeignDone { .. } => { RedemptionState::::remove(who, investment_id); Ok(Some(RedeemState::NoState)) } - InnerRedeemState::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } => { - let new_state = - state.swap_inner_state(InnerRedeemState::Redeeming { redeem_amount }); + RedeemState::RedeemingAndSwapIntoForeignDone { redeem_amount, .. } => { + let new_state = RedeemState::Redeeming { redeem_amount }; RedemptionState::::insert(who, investment_id, new_state); Ok(Some(new_state)) } @@ -687,36 +678,23 @@ impl Pallet { } }); - // Need to check if `SwapReturnDone` is part of inner state without + // Need to check if `SwapReturnDone` is part of state without // `ActiveSwapIntoForeignCurrency` as this implies the successful termination of // a collect (with swap into foreign currency). If this is the case, the // returned redeem state needs to be updated as well. - let returning_redeem_state = match maybe_redeem_state { - Some(RedeemState::InvestedAnd { inner, .. }) - | Some(RedeemState::NotInvestedAnd { inner }) => { - if let Some(collected_redeem_state) = Self::apply_collect_redeem_transition( - who, - investment_id, - maybe_redeem_state.unwrap_or_default(), - inner, - )? { - Ok(Some(collected_redeem_state)) - } else { - Ok(maybe_redeem_state) - } - } - Some(_) => { - RedemptionState::::mutate(who, investment_id, |current_redeem_state| { - // Update and emit event on mismatch - if let Some(state) = maybe_redeem_state { - *current_redeem_state = state - } - Ok(maybe_redeem_state) - }) - } - None => Ok(maybe_redeem_state), - } - .map_err(|e: DispatchError| e)?; + let returning_redeem_state = Self::apply_collect_redeem_transition( + who, + investment_id, + maybe_redeem_state.unwrap_or_default(), + )? + .map(|collected_redeem_state| Some(collected_redeem_state)) + .unwrap_or(maybe_redeem_state) + .map(|redeem_state| { + RedemptionState::::mutate(who, investment_id, |current_redeem_state| { + *current_redeem_state = redeem_state; + }); + redeem_state + }); Ok((maybe_invest_state, returning_redeem_state)) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 4df0b0b494..2d228bbb69 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -15,19 +15,10 @@ use cfg_types::investments::Swap; use frame_support::{dispatch::fmt::Debug, ensure}; use sp_runtime::{ traits::{EnsureAdd, EnsureSub}, - ArithmeticError, DispatchError, + DispatchError, }; -use crate::types::{ - InnerRedeemState, - InnerRedeemState::{ - ActiveSwapIntoForeignCurrency, ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - Redeeming, RedeemingAndActiveSwapIntoForeignCurrency, - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone, - RedeemingAndSwapIntoForeignDone, SwapIntoForeignDone, - }, - RedeemState, RedeemTransition, -}; +use crate::types::{RedeemState, RedeemTransition}; impl RedeemState where @@ -55,106 +46,11 @@ where } } - /// Returns the potentially existing active swap into foreign currency of - /// the inner state: - /// * If the inner state includes `ActiveSwapIntoForeignCurrency`, it - /// returns the corresponding `Some(swap)`. - /// * Else, it returns `None`. - pub(crate) fn get_active_swap(&self) -> Option> { - match self { - Self::NoState => None, - Self::Invested { .. } => None, - Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { - inner.get_active_swap() - } - } - } - - /// Returns the redeeming amount of the inner state, if existent. Else - /// returns zero. - pub(crate) fn get_redeeming_amount(&self) -> Balance { - match self { - Self::NoState | Self::Invested { .. } => Balance::zero(), - Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => { - inner.get_redeeming_amount() - } - } - } - - pub(crate) fn increase_invested_amount(&self, amount: Balance) -> Result { - match *self { - Self::NoState => Ok(Self::Invested { - invest_amount: amount, - }), - Self::Invested { invest_amount } => Ok(Self::Invested { - invest_amount: invest_amount.ensure_add(amount)?, - }), - Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { - invest_amount: amount, - inner, - }), - Self::InvestedAnd { - invest_amount, - inner, - } => Ok(Self::InvestedAnd { - invest_amount: invest_amount.ensure_add(amount)?, - inner, - }), - } - } - - /// Exchanges the inner state of `RedeemState::InvestedAnd` as well as - /// `RedeemState::NotInvestedAnd` with the provided one similar to a memory - /// swap. - pub(crate) fn swap_inner_state(&self, inner: InnerRedeemState) -> Self { - match *self { - Self::InvestedAnd { invest_amount, .. } => Self::InvestedAnd { - invest_amount, - inner, - }, - Self::NotInvestedAnd { .. } => Self::NotInvestedAnd { inner }, - _ => *self, - } - } - - /// Reduce the amount of an active swap (into foreign currency) of the - /// `InnerRedeemState` by the provided value: - /// * If the provided value equals the swap amount, the state is - /// transitioned into `*AndSwapIntoForeignDone`. - /// * Else, it is transitioned into - /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. - /// - /// NOTE: Throws if any of the following holds true: - /// * The outer `RedeemState` is not `InvestedAnd` or `NotInvested` as this - /// implies there is no active swap. - /// * The inner state is not an active swap, i.e. the state does not include - /// `ActiveSwapIntoForeignCurrency`. - /// * The reducible amount exceeds the active swap amount. - pub(crate) fn fulfill_active_swap_amount( - &self, - amount: Balance, - ) -> Result { - match self { - Self::InvestedAnd { inner, .. } | Self::NotInvestedAnd { inner } => Ok( - Self::swap_inner_state(self, inner.fulfill_active_swap_amount(amount)?), - ), - _ => Err(DispatchError::Other( - "Cannot alter active swap amount for RedeemStates without swap", - )), - } - } -} - -impl InnerRedeemState -where - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - Currency: Clone + Copy + PartialEq + Debug, -{ /// Returns the potentially existing active swap into foreign currency: /// * If the state includes `ActiveSwapIntoForeignCurrency`, it returns the /// corresponding `Some(swap)`. /// * Else, it returns `None`. - fn get_active_swap(&self) -> Option> { + pub(crate) fn get_active_swap(&self) -> Option> { match *self { Self::ActiveSwapIntoForeignCurrency { swap } | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } @@ -167,7 +63,7 @@ where } /// Returns the redeeming amount if existent. Else returns zero. - fn get_redeeming_amount(&self) -> Balance { + pub(crate) fn get_redeeming_amount(&self) -> Balance { match *self { Self::Redeeming { redeem_amount } | Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, .. } @@ -180,6 +76,89 @@ where } } + /// Either adds a non existing redeeming amount to the state or overwrites + /// it. + /// * If the value is not zero and the state involves `Redeeming`: Sets the + /// amount. + /// * Else if the value is not zero and the state does not involve + /// `Redeeming`: Adds `Redeeming` to the state with the corresponding + /// amount. + /// * If the value is zero and the state includes `Redeeming`: Removes + /// `Redeeming` from the state. + /// * Else throws. + fn set_redeem_amount(&self, amount: Balance) -> Result { + if amount.is_zero() { + return Self::remove_redeem_amount(self); + } + match *self { + Self::NoState | Self::Redeeming { .. } => Ok(Self::Redeeming { + redeem_amount: amount, + }), + Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { + Ok(Self::RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount: amount, + swap, + }) + } + Self::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + Ok(Self::RedeemingAndSwapIntoForeignDone { + redeem_amount: amount, + done_swap, + }) + } + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + .. + } => Ok( + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + redeem_amount: amount, + swap, + done_amount, + }, + ), + Self::ActiveSwapIntoForeignCurrency { swap } => { + Ok(Self::RedeemingAndActiveSwapIntoForeignCurrency { + swap, + redeem_amount: amount, + }) + } + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok( + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + redeem_amount: amount, + }, + ), + Self::SwapIntoForeignDone { done_swap } => Ok(Self::RedeemingAndSwapIntoForeignDone { + done_swap, + redeem_amount: amount, + }), + } + } + + /// Removes `Redeeming` from the state. + fn remove_redeem_amount(&self) -> Result { + match *self { + Self::Redeeming { .. } => Ok(Self::NoState), + Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { + Ok(Self::ActiveSwapIntoForeignCurrency { swap }) + } + Self::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + Ok(Self::SwapIntoForeignDone { done_swap }) + } + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + swap, + done_amount, + .. + } => Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), + // Throw for states without `Redeeming` + _ => Err(DispatchError::Other( + "Cannot remove redeeming amount of redeem state which does not include `Redeeming`", + )), + } + } + /// Reduce the amount of an active swap (into foreign currency) by the /// provided value: /// * Throws if there is no active swap, i.e. the state does not include @@ -189,7 +168,10 @@ where /// transitioned into `*AndSwapIntoForeignDone`. /// * Else, it is transitioned into /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. - fn fulfill_active_swap_amount(&self, amount: Balance) -> Result { + pub(crate) fn fulfill_active_swap_amount( + &self, + amount: Balance, + ) -> Result { match self { Self::ActiveSwapIntoForeignCurrency { swap } => { if amount == swap.amount { @@ -275,97 +257,21 @@ where } } _ => Err(DispatchError::Other( - "Invalid inner redeem state when fulfilling active swap amount", + "Invalid redeem state when fulfilling active swap amount", )), } } - /// Removes `Redeeming` from the state. - fn remove_redeem_amount(&self) -> Result { - match *self { - Redeeming { .. } => Err(DispatchError::Other("Outer RedeemState must be transitioned to Self::Invested")), - RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => Ok(ActiveSwapIntoForeignCurrency { swap }), - RedeemingAndSwapIntoForeignDone { done_swap, .. } => Ok(SwapIntoForeignDone { done_swap }), - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. } => Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount }), - // Throw for states without `Redeeming` - _ => Err(DispatchError::Other("Cannot remove redeeming amount of inner redeem state which does not include `Redeeming`")), - } - } - - /// Either adds a non existing redeeming amount to the state or overwrites - /// it. - /// * If the value is not zero and the state involves `Redeeming`: Sets the - /// amount. - /// * Else if the value is not zero and the state does not involve - /// `Redeeming`: Adds `Redeeming` to the state with the corresponding - /// amount. - /// * If the value is zero and the state includes `Redeeming`: Removes - /// `Redeeming` from the state. - /// * Else throws. - fn set_redeem_amount(&self, amount: Balance) -> Result { - if amount.is_zero() { - return Self::remove_redeem_amount(self); - } - match *self { - Redeeming { .. } => Ok(Redeeming { - redeem_amount: amount, - }), - RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { - Ok(RedeemingAndActiveSwapIntoForeignCurrency { - redeem_amount: amount, - swap, - }) - } - RedeemingAndSwapIntoForeignDone { done_swap, .. } => { - Ok(RedeemingAndSwapIntoForeignDone { - redeem_amount: amount, - done_swap, - }) - } - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap, - done_amount, - .. - } => Ok( - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - redeem_amount: amount, - swap, - done_amount, - }, - ), - ActiveSwapIntoForeignCurrency { swap } => { - Ok(RedeemingAndActiveSwapIntoForeignCurrency { - swap, - redeem_amount: amount, - }) - } - ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => Ok( - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { - swap, - done_amount, - redeem_amount: amount, - }, - ), - SwapIntoForeignDone { done_swap } => Ok(RedeemingAndSwapIntoForeignDone { - done_swap, - redeem_amount: amount, - }), - } - } - - /// Transition all inner states which include - /// `ActiveSwapIntoForeignCurrency`. The transitioned state either includes - /// `*SwapIntoForeignDone` or - /// `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. + /// Transition all states which include `ActiveSwapIntoForeignCurrency`. + /// + /// The resulting transitioned state either includes `*SwapIntoForeignDone` + /// or `*ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone`. /// /// Also supports non-foreign swaps, i.e. those with matching in and out /// currency. /// /// Throws if the fulfilled swap direction is not into foreign currency or /// if the amount exceeds the states active swap amount. - /// - /// NOTE: We can ignore all states which do not include - /// `ActiveSwapIntoForeignCurrency`. fn transition_fulfilled_swap_order( &self, fulfilled_swap: Swap, @@ -378,9 +284,7 @@ where && swap.currency_out == fulfilled_swap.currency_out }) .unwrap_or(true), - DispatchError::Other( - "Invalid inner redeem state when transitioning fulfilled swap order" - ) + DispatchError::Other("Invalid redeem state when transitioning fulfilled swap order") ); let Swap { amount, .. } = fulfilled_swap; @@ -388,9 +292,9 @@ where // Edge case: if currency_in matches currency_out, we can immediately fulfill // the swap match *self { - ActiveSwapIntoForeignCurrency { swap } => { + Self::ActiveSwapIntoForeignCurrency { swap } => { if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap @@ -398,13 +302,13 @@ where done_amount: amount, }) } else { - Ok(SwapIntoForeignDone { done_swap: swap }) + Ok(Self::SwapIntoForeignDone { done_swap: swap }) } } - ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount } => { let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { - Ok(ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap @@ -412,7 +316,7 @@ where done_amount, }) } else { - Ok(SwapIntoForeignDone { + Ok(Self::SwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap @@ -420,13 +324,13 @@ where }) } } - RedeemingAndActiveSwapIntoForeignCurrency { + Self::RedeemingAndActiveSwapIntoForeignCurrency { redeem_amount, swap, } => { if amount < swap.amount && swap.currency_in != swap.currency_out { Ok( - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap @@ -436,13 +340,13 @@ where }, ) } else { - Ok(RedeemingAndSwapIntoForeignDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { done_swap: swap, redeem_amount, }) } } - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { redeem_amount, swap, done_amount, @@ -450,7 +354,7 @@ where let done_amount = done_amount.ensure_add(amount)?; if amount < swap.amount && swap.currency_in != swap.currency_out { Ok( - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: Swap { amount: swap.amount - amount, ..swap @@ -460,7 +364,7 @@ where }, ) } else { - Ok(RedeemingAndSwapIntoForeignDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { done_swap: Swap { amount: done_amount, ..swap @@ -470,7 +374,7 @@ where } } _ => Err(DispatchError::Other( - "Invalid inner redeem state when transitioning fulfilled swap order", + "Invalid redeem state when transitioning fulfilled swap order", )), } } @@ -483,28 +387,28 @@ where collected_swap: Swap, ) -> Result { match *self { - Redeeming { .. } => { + Self::Redeeming { .. } => { if amount_redeeming.is_zero() { - Ok(SwapIntoForeignDone { + Ok(Self::SwapIntoForeignDone { done_swap: collected_swap, }) } else { - Ok(RedeemingAndSwapIntoForeignDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { redeem_amount: amount_redeeming, done_swap: collected_swap, }) } } - RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + Self::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { let swap = Swap { amount: done_swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap }; if amount_redeeming.is_zero() { - Ok(SwapIntoForeignDone { done_swap: swap }) + Ok(Self::SwapIntoForeignDone { done_swap: swap }) } else { - Ok(RedeemingAndSwapIntoForeignDone { + Ok(Self::RedeemingAndSwapIntoForeignDone { redeem_amount: amount_redeeming, done_swap: swap, }) @@ -562,7 +466,7 @@ where // Either remove or update redeeming amount and add/update swap into foreign // currency match *self { - Redeeming { .. } => { + Self::Redeeming { .. } => { if amount_redeeming.is_zero() { Ok(Self::ActiveSwapIntoForeignCurrency { swap: collected_swap, @@ -574,7 +478,7 @@ where }) } } - RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { + Self::RedeemingAndActiveSwapIntoForeignCurrency { swap, .. } => { let new_swap = Swap { amount: swap.amount.ensure_add(collected_swap.amount)?, ..collected_swap @@ -588,7 +492,7 @@ where }) } } - RedeemingAndSwapIntoForeignDone { done_swap, .. } => { + Self::RedeemingAndSwapIntoForeignDone { done_swap, .. } => { if amount_redeeming.is_zero() { Ok(Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: collected_swap, @@ -604,7 +508,7 @@ where ) } } - RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Self::RedeemingAndActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, done_amount, .. @@ -641,153 +545,42 @@ where Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, Currency: Clone + Copy + PartialEq + Debug, { - /// Handle `increase` transitions depicted by `msg::increase` edges in the - /// redeem state diagram: - /// * If the current state includes a processed investment, i.e. is either - /// `RedeemState::Invested` or `RedeemState::InvestedAnd(..)`, decreases - /// the invest amount and increases the redeeming amount. Throws if the - /// investment amount is exceeded as this reflects the max redeeming - /// amount. - /// * Else throws for incorrect pre state. + /// Increments the unprocessed redeeming amount or adds `Redeeming*` to the + /// state with the provided amount. fn handle_increase(&self, amount: Balance) -> Result { - match self { - Self::Invested { invest_amount } => { - if &amount == invest_amount { - Ok(Self::NotInvestedAnd { - inner: Redeeming { - redeem_amount: amount, - }, - }) - } else { - Ok(Self::InvestedAnd { - invest_amount: invest_amount.ensure_sub(amount)?, - inner: Redeeming { - redeem_amount: amount, - }, - }) - } - } - Self::InvestedAnd { - invest_amount, - inner, - } => { - let redeeming_amount = self.get_redeeming_amount().ensure_add(amount)?; - if &amount == invest_amount { - Ok(Self::NotInvestedAnd { - inner: inner.set_redeem_amount(redeeming_amount)?, - }) - } else { - Ok(Self::InvestedAnd { - invest_amount: invest_amount.ensure_sub(amount)?, - inner: inner.set_redeem_amount(redeeming_amount)?, - }) - } - } - _ => Err(DispatchError::Other( - "Invalid redeem state when transitioning an increase", - )), - } + Self::set_redeem_amount(&self, Self::get_redeeming_amount(&self).ensure_add(amount)?) } - /// Handle `decrease` transitions depicted by `msg::decrease` edges in the - /// redeem state diagram: - /// * If the current inner state includes an unprocessed redemption, i.e. is - /// `InnerRedeemState::Redeeming`, decreases the redeeming amount up to - /// its max. Throws if the decrement amount exceeds the previously - /// increased redemption amount. - /// * Else throws for incorrect pre state. + /// Decrement the unprocessed redeeming amount. I.e., if the state includes + /// `Redeeming*`, decreases the redeeming amount. fn handle_decrease(&self, amount: Balance) -> Result { - let error_not_redeeming = Err(DispatchError::Other( - "Invalid redeem state when transitioning a decrease", - )); - - match self.get_redeeming_amount() { - amount if amount.is_zero() => error_not_redeeming, - // Can only decrease up to current redeeming amount - redeem_amount if redeem_amount < amount => { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) - } - // Entire redeeming amount becomes invested amount, i.e. remove `Redeeming` from inner - // state - redeem_amount if redeem_amount == amount => match self { - Self::NoState | Self::Invested { .. } => error_not_redeeming, - Self::NotInvestedAnd { inner } => match inner { - Redeeming { .. } => Ok(Self::Invested { - invest_amount: amount, - }), - _ => Ok(Self::InvestedAnd { - invest_amount: amount, - inner: inner.set_redeem_amount(Balance::zero())?, - }), - }, - Self::InvestedAnd { - invest_amount, - inner, - } => { - let invest_amount = invest_amount.ensure_add(amount)?; - match inner { - Redeeming { .. } => Ok(Self::Invested { invest_amount }), - _ => Ok(Self::InvestedAnd { - invest_amount, - inner: inner.set_redeem_amount(Balance::zero())?, - }), - } - } - }, - // Partial redeeming amount becomes invested amount, i.e. keep `Redeeming` in inner - // state - old_redeem_amount => { - let redeem_amount = old_redeem_amount.ensure_sub(amount)?; - - match self { - Self::NoState | Self::Invested { .. } => error_not_redeeming, - Self::NotInvestedAnd { inner } => Ok(Self::InvestedAnd { - invest_amount: amount, - inner: inner.set_redeem_amount(redeem_amount)?, - }), - Self::InvestedAnd { - invest_amount, - inner, - } => { - let invest_amount = invest_amount.ensure_add(amount)?; - Ok(Self::InvestedAnd { - invest_amount, - inner: inner.set_redeem_amount(redeem_amount)?, - }) - } - } - } - } + Self::set_redeem_amount(&self, Self::get_redeeming_amount(&self).ensure_sub(amount)?) } - /// Update the inner state if it includes `ActiveSwapIntoForeignCurrency`. + /// Update the state if it includes `ActiveSwapIntoForeignCurrency`. fn handle_fulfilled_swap_order( &self, swap: Swap, ) -> Result { match self { - Self::NotInvestedAnd { inner } | Self::InvestedAnd { inner, .. } => Ok( - Self::swap_inner_state(self, inner.transition_fulfilled_swap_order(swap)?), - ), - _ => Err(DispatchError::Other( + Self::NoState => Err(DispatchError::Other( "Invalid redeem state when transitioning a fulfilled order", )), + state => state.transition_fulfilled_swap_order(swap), } } - /// Update the inner state if it includes `Redeeming`. + /// Update the state if it includes `Redeeming`. fn handle_collect( &self, amount_redeeming: Balance, swap: Swap, ) -> Result { match self { - RedeemState::NoState | RedeemState::Invested { .. } => Err(DispatchError::Other( + Self::NoState => Err(DispatchError::Other( "Invalid redeem state when transitioning collect", )), - RedeemState::NotInvestedAnd { inner } | RedeemState::InvestedAnd { inner, .. } => Ok( - Self::swap_inner_state(self, inner.transition_collect(amount_redeeming, swap)?), - ), + state => state.transition_collect(amount_redeeming, swap), } } } diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 54b9493b04..8ee0856a14 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -412,6 +412,4 @@ pub mod pallet { Error::::RedeemError(error) } } - - // TODO: Add call to allow payment currency } diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 10e5106846..73adaab924 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -30,7 +30,8 @@ pub enum TokenSwapReason { Redemption, } -// TODO: Docs +/// Restriction of `pallet_foreign_investments::Config` trait to support +/// currency conversion in the `InvestState`. pub trait InvestStateConfig { type Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug + Zero; type CurrencyId: Clone + Copy + PartialEq + Debug; @@ -289,31 +290,6 @@ pub enum RedeemState< /// chain state, i.e. if this state is the result of applying transition(s), /// then the corresponding `RedemptionState` will be cleared. NoState, - /// There is no pending redemption process at this point. The investment can - /// be redeemed up to the invested amount (after fulfillment). - Invested { invest_amount: Balance }, - /// There is no remaining investment such that the redemption cannot be - /// increased at this point. - NotInvestedAnd { - inner: InnerRedeemState, - }, - /// There is a remaining invested amount such that the redemption can be - /// increased up to the remaining invested amount (after fulfillment). - InvestedAnd { - invest_amount: Balance, - inner: InnerRedeemState, - }, -} - -/// Reflects all possible redeem states independent of whether an investment is -/// still active or not in the actual `RedeemState`. -#[derive( - Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, -)] -pub enum InnerRedeemState< - Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - Currency: Clone + Copy + PartialEq + Debug, -> { /// The redemption is pending until it is processed during epoch execution. Redeeming { redeem_amount: Balance }, /// The redemption was fully processed and collected and is currently @@ -376,4 +352,3 @@ pub enum RedeemTransition< CollectRedemption(Balance, Swap), } -// impl InvestState {} diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 7c46af5010..4a35d270c0 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -50,7 +50,7 @@ use frame_support::{ }; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use pallet_foreign_investments::{ - types::{InnerRedeemState, InvestState, RedeemState}, + types::{InvestState, RedeemState}, CollectedRedemption, InvestmentState, RedemptionState, }; use pallet_investments::CollectOutcome; @@ -465,10 +465,8 @@ mod same_currencies { assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); assert_eq!( RedemptionState::::get(&investor, default_investment_id()), - RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: amount * 2, - } + RedeemState::Redeeming { + redeem_amount: amount * 2, } ); }); @@ -541,11 +539,8 @@ mod same_currencies { == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), investment_id: default_investment_id(), - state: RedeemState::InvestedAnd { - invest_amount: decrease_amount, - inner: InnerRedeemState::Redeeming { + state: RedeemState::Redeeming { redeem_amount: final_amount - } } } .into() @@ -631,10 +626,9 @@ mod same_currencies { // Foreign RedemptionState should be updated assert!(System::events().iter().any(|e| { e.event - == pallet_foreign_investments::Event::::ForeignRedemptionUpdated { + == pallet_foreign_investments::Event::::ForeignRedemptionCleared { investor: investor.clone(), investment_id: default_investment_id(), - state: RedeemState::Invested { invest_amount: redeem_amount }, } .into() })); @@ -843,11 +837,8 @@ mod same_currencies { )); assert_eq!( RedemptionState::::get(&investor, default_investment_id()), - RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { redeem_amount } - } + RedeemState::Redeeming { redeem_amount } ); - // Collecting through investments should denote amounts and transition // state assert_ok!(Investments::collect_redemptions_for( @@ -881,10 +872,8 @@ mod same_currencies { ),); assert_eq!( RedemptionState::::get(&investor, default_investment_id()), - RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: redeem_amount / 2, - } + RedeemState::Redeeming { + redeem_amount: redeem_amount / 2, } ); assert!(System::events().iter().any(|e| e.event @@ -1784,10 +1773,8 @@ mod setup { assert_eq!( RedemptionState::::get(&investor, default_investment_id()), - RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: amount - } + RedeemState::Redeeming { + redeem_amount: amount } ); // Verify redemption was transferred into investment account @@ -1814,11 +1801,9 @@ mod setup { pallet_foreign_investments::Event::::ForeignRedemptionUpdated { investor: investor.clone(), investment_id: default_investment_id(), - state: RedeemState::NotInvestedAnd { - inner: InnerRedeemState::Redeeming { - redeem_amount: amount - } - }, + state: RedeemState::Redeeming { + redeem_amount: amount + } } .into() ); From abab7d176c18f91f454d781429889fcddcc25e39 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 6 Sep 2023 17:48:51 +0200 Subject: [PATCH 77/96] feat: update messages --- pallets/liquidity-pools/src/lib.rs | 106 +++++++++++-- pallets/liquidity-pools/src/message.rs | 126 +++++++++++++++- pallets/pool-system/src/tranches.rs | 4 +- .../liquidity_pools/add_allow_upgrade.rs | 142 ++++++++++++++++-- 4 files changed, 345 insertions(+), 33 deletions(-) diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index c0f02c0498..b8d6d2684a 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -436,14 +436,11 @@ pub mod pallet { ); // Look up the metadata of the tranche token - let currency_id = Self::derive_invest_id(pool_id, tranche_id)?; - let metadata = T::AssetRegistry::metadata(¤cy_id.into()) + let investment_id = Self::derive_invest_id(pool_id, tranche_id)?; + let metadata = T::AssetRegistry::metadata(&investment_id.into()) .ok_or(Error::::TrancheMetadataNotFound)?; let token_name = vec_to_fixed_array(metadata.name); let token_symbol = vec_to_fixed_array(metadata.symbol); - let price = T::TrancheTokenPrice::get(pool_id, tranche_id) - .ok_or(Error::::MissingTranchePrice)? - .price; // Send the message to the domain T::OutboundQueue::submit( @@ -455,34 +452,54 @@ pub mod pallet { decimals: metadata.decimals.saturated_into(), token_name, token_symbol, - price, }, )?; Ok(()) } - /// Update the price of a tranche token + /// Update the price of a tranche token. + /// + /// By ensuring that registered currency location matches the specified + /// 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::call_index(4)] pub fn update_token_price( origin: OriginFor, pool_id: T::PoolId, tranche_id: T::TrancheId, - domain: Domain, + currency_id: CurrencyIdOf, + destination: Domain, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; + // TODO(future): Once we diverge from 1-to-1 conversions for foreign and pool + // currencies, this price must be first converted into the currency_id and then + // re-denominated to 18 decimals (i.e. `BalanceRatio` precision) let price = T::TrancheTokenPrice::get(pool_id, tranche_id) .ok_or(Error::::MissingTranchePrice)? .price; + // Check that the registered asset location matches the destination + match Self::try_get_wrapped_token(¤cy_id)? { + LiquidityPoolsWrappedToken::EVM { chain_id, .. } => { + ensure!( + Domain::EVM(chain_id) == destination, + Error::::InvalidDomain + ); + } + } + let currency = Self::try_get_general_index(currency_id)?; + T::OutboundQueue::submit( who, - domain, + destination, Message::UpdateTrancheTokenPrice { pool_id, tranche_id, + currency, price, }, )?; @@ -695,7 +712,7 @@ pub mod pallet { tranche_id: T::TrancheId, currency_id: CurrencyIdOf, ) -> DispatchResult { - // TODO(subsequent PR): In the future, should be permissioned by trait which + // TODO(future): In the future, should be permissioned by trait which // does not exist yet. // See spec: https://centrifuge.hackmd.io/SERpps-URlG4hkOyyS94-w?view#fn-add_pool_currency let who = ensure_signed(origin)?; @@ -746,6 +763,75 @@ pub mod pallet { Message::ScheduleUpgrade { contract }, ) } + + /// Schedule an upgrade of an EVM-based liquidity pool contract instance + #[pallet::weight(10_000)] + #[pallet::call_index(11)] + pub fn cancel_upgrade( + origin: OriginFor, + evm_chain_id: EVMChainId, + contract: [u8; 20], + ) -> DispatchResult { + ensure_root(origin)?; + + T::OutboundQueue::submit( + T::TreasuryAccount::get(), + Domain::EVM(evm_chain_id), + Message::CancelUpgrade { contract }, + ) + } + + /// Update the tranche token name and symbol on the specified domain + /// + /// NOTE: Pulls the metadata from the `AssetRegistry` and thus requires + /// the pool admin to have updated the tranche tokens metadata there + /// beforehand. + #[pallet::weight(10_000)] + #[pallet::call_index(12)] + pub fn update_tranche_token_metadata( + origin: OriginFor, + pool_id: T::PoolId, + tranche_id: T::TrancheId, + domain: Domain, + ) -> 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), + who.clone(), + Role::PoolRole(PoolRole::PoolAdmin) + ), + Error::::NotPoolAdmin + ); + let investment_id = Self::derive_invest_id(pool_id, tranche_id)?; + let metadata = T::AssetRegistry::metadata(&investment_id.into()) + .ok_or(Error::::TrancheMetadataNotFound)?; + #[cfg(feature = "std")] + { + dbg!(&metadata); + } + let token_name = vec_to_fixed_array(metadata.name); + let token_symbol = vec_to_fixed_array(metadata.symbol); + + T::OutboundQueue::submit( + T::TreasuryAccount::get(), + domain, + Message::UpdateTrancheTokenMetadata { + pool_id, + tranche_id, + token_name, + token_symbol, + }, + ) + } + + // TODO(@future): pub fn update_tranche_investment_limit } impl Pallet { diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index e1bce77044..590344897c 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -72,7 +72,6 @@ where token_name: [u8; TOKEN_NAME_SIZE], token_symbol: [u8; TOKEN_SYMBOL_SIZE], decimals: u8, - price: Rate, }, /// Update the price of a tranche token on the target domain. /// @@ -80,6 +79,7 @@ where UpdateTrancheTokenPrice { pool_id: PoolId, tranche_id: TrancheId, + currency: u128, price: Rate, }, /// Whitelist an address for the specified pair of pool and tranche token on @@ -322,6 +322,35 @@ where /// The EVM contract address contract: [u8; 20], }, + /// Cancel the scheduled process for an EVM address to become rely-able by + /// the gateway. Intended to be used via governance to execute EVM spells. + /// + /// Directionality: Centrifuge -> EVM Domain. + CancelUpgrade { + /// The EVM contract address + contract: [u8; 20], + }, + /// Updates the name and symbol of a tranche token. + /// + /// NOTE: We do not allow updating the decimals as this would require + /// migrating all associated balances. + /// + /// Directionality: Centrifuge -> EVM Domain. + UpdateTrancheTokenMetadata { + pool_id: PoolId, + tranche_id: TrancheId, + token_name: [u8; TOKEN_NAME_SIZE], + token_symbol: [u8; TOKEN_SYMBOL_SIZE], + }, + /// Update the investment limit of the specified tranche token. Disables + /// investment if the amount is set to zero. + /// + /// Directionality: Centrifuge -> EVM Domain. + UpdateTrancheInvestmentLimit { + pool_id: PoolId, + tranche_id: TrancheId, + amount: Balance, + }, } impl< @@ -362,6 +391,9 @@ impl< Self::CancelInvestOrder { .. } => 19, Self::CancelRedeemOrder { .. } => 20, Self::ScheduleUpgrade { .. } => 21, + Self::CancelUpgrade { .. } => 22, + Self::UpdateTrancheTokenMetadata { .. } => 23, + Self::UpdateTrancheInvestmentLimit { .. } => 24, } } } @@ -397,7 +429,6 @@ impl< token_name, token_symbol, decimals, - price, } => encoded_message( self.call_type(), vec![ @@ -406,16 +437,21 @@ impl< token_name.encode(), token_symbol.encode(), decimals.encode(), - encode_be(price), ], ), Message::UpdateTrancheTokenPrice { pool_id, tranche_id, + currency, price, } => encoded_message( self.call_type(), - vec![encode_be(pool_id), tranche_id.encode(), encode_be(price)], + vec![ + encode_be(pool_id), + tranche_id.encode(), + encode_be(currency), + encode_be(price), + ], ), Message::UpdateMember { pool_id, @@ -654,6 +690,31 @@ impl< Message::ScheduleUpgrade { contract } => { encoded_message(self.call_type(), vec![contract.to_vec()]) } + Message::CancelUpgrade { contract } => { + encoded_message(self.call_type(), vec![contract.to_vec()]) + } + Message::UpdateTrancheTokenMetadata { + pool_id, + tranche_id, + token_name, + token_symbol, + } => encoded_message( + self.call_type(), + vec![ + encode_be(pool_id), + tranche_id.encode(), + token_name.encode(), + token_symbol.encode(), + ], + ), + Message::UpdateTrancheInvestmentLimit { + pool_id, + tranche_id, + amount, + } => encoded_message( + self.call_type(), + vec![encode_be(pool_id), tranche_id.encode(), encode_be(amount)], + ), } } @@ -679,11 +740,11 @@ impl< token_name: decode::(input)?, token_symbol: decode::(input)?, decimals: decode::<1, _, _>(input)?, - price: decode_be_bytes::<16, _, _>(input)?, }), 5 => Ok(Self::UpdateTrancheTokenPrice { pool_id: decode_be_bytes::<8, _, _>(input)?, tranche_id: decode::<16, _, _>(input)?, + currency: decode_be_bytes::<16, _, _>(input)?, price: decode_be_bytes::<16, _, _>(input)?, }), 6 => Ok(Self::UpdateMember { @@ -791,6 +852,20 @@ impl< 21 => Ok(Self::ScheduleUpgrade { contract: decode::<20, _, _>(input)?, }), + 22 => Ok(Self::CancelUpgrade { + contract: decode::<20, _, _>(input)?, + }), + 23 => Ok(Self::UpdateTrancheTokenMetadata { + pool_id: decode_be_bytes::<8, _, _>(input)?, + tranche_id: decode::<16, _, _>(input)?, + token_name: decode::(input)?, + token_symbol: decode::(input)?, + }), + 24 => Ok(Self::UpdateTrancheInvestmentLimit { + pool_id: decode_be_bytes::<8, _, _>(input)?, + tranche_id: decode::<16, _, _>(input)?, + amount: decode_be_bytes::<16, _, _>(input)?, + }), _ => Err(codec::Error::from( "Unsupported decoding for this Message variant", )), @@ -933,9 +1008,8 @@ mod tests { token_name: vec_to_fixed_array("Some Name".to_string().into_bytes()), token_symbol: vec_to_fixed_array("SYMBOL".to_string().into_bytes()), decimals: 15, - price: Rate::one(), }, - "040000000000000001811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c00000000000000000000000000000000000000000000000000000f00000000033b2e3c9fd0803ce8000000", + "040000000000000001811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c00000000000000000000000000000000000000000000000000000f", ) } @@ -945,9 +1019,10 @@ mod tests { LiquidityPoolsMessage::UpdateTrancheTokenPrice { pool_id: 1, tranche_id: default_tranche_id(), + currency: TOKEN_ID, price: Rate::one(), }, - "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b00000000033b2e3c9fd0803ce8000000", + "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b0000000000000000000000000eb5ec7b00000000033b2e3c9fd0803ce8000000", ) } @@ -1198,6 +1273,41 @@ mod tests { ) } + #[test] + fn cancel_upgrade() { + test_encode_decode_identity( + LiquidityPoolsMessage::CancelUpgrade { + contract: default_address_20(), + }, + "161231231231231231231231231231231231231231", + ) + } + + #[test] + fn update_tranche_token_metadata() { + test_encode_decode_identity( + LiquidityPoolsMessage::UpdateTrancheTokenMetadata { + pool_id: 1, + tranche_id: default_tranche_id(), + token_name: vec_to_fixed_array("Some Name".to_string().into_bytes()), + token_symbol: vec_to_fixed_array("SYMBOL".to_string().into_bytes()), + }, + "170000000000000001811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c0000000000000000000000000000000000000000000000000000", + ) + } + + #[test] + fn update_tranche_investment_limit() { + test_encode_decode_identity( + LiquidityPoolsMessage::UpdateTrancheInvestmentLimit { + pool_id: 1, + tranche_id: default_tranche_id(), + amount: AMOUNT, + }, + "180000000000000001811acd5b3f17c06841c7e41e9e04cb1b000000000052b7d2dcc80cd2e4000000", + ) + } + /// Verify the identity property of decode . encode on a Message value and /// that it in fact encodes to and can be decoded from a given hex string. fn test_encode_decode_identity( diff --git a/pallets/pool-system/src/tranches.rs b/pallets/pool-system/src/tranches.rs index 59bfcd5a11..232ff06a31 100644 --- a/pallets/pool-system/src/tranches.rs +++ b/pallets/pool-system/src/tranches.rs @@ -171,8 +171,8 @@ where } /// Update the debt of a Tranche by multiplying with the accrued interest - /// since the last update: debt = debt * interest_rate_per_second ^ (now - /// - last_update) + /// since the last update: + /// debt = debt * interest_rate_per_second ^ (now - last_update) pub fn accrue(&mut self, now: Moment) -> Result<(), ArithmeticError> { let delta = now - self.last_updated_interest; let interest = self.interest_rate_per_sec(); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index 680552aebf..2c9508c78e 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -88,7 +88,7 @@ fn add_pool() { LiquidityPools::add_pool( RuntimeOrigin::signed(ALICE.into()), pool_id, - Domain::EVM(1284), + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), ), pallet_liquidity_pools::Error::::PoolNotFound ); @@ -101,7 +101,7 @@ fn add_pool() { LiquidityPools::add_pool( RuntimeOrigin::signed(ALICE.into()), pool_id, - Domain::EVM(1284), + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), ), pallet_liquidity_pools::Error::::NotPoolAdmin ); @@ -110,7 +110,7 @@ fn add_pool() { assert_ok!(LiquidityPools::add_pool( RuntimeOrigin::signed(BOB.into()), pool_id, - Domain::EVM(1284), + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), )); }); } @@ -140,7 +140,7 @@ fn add_tranche() { RuntimeOrigin::signed(ALICE.into()), pool_id, nonexistent_tranche, - Domain::EVM(1284), + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), ), pallet_liquidity_pools::Error::::TrancheNotFound ); @@ -152,7 +152,7 @@ fn add_tranche() { RuntimeOrigin::signed(ALICE.into()), pool_id, tranche_id, - Domain::EVM(1284), + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), ), pallet_liquidity_pools::Error::::NotPoolAdmin ); @@ -163,8 +163,21 @@ fn add_tranche() { RuntimeOrigin::signed(BOB.into()), pool_id, tranche_id, - Domain::EVM(1284), + 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!( + LiquidityPools::update_tranche_token_metadata( + RuntimeOrigin::signed(BOB.into()), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheMetadataNotFound + ); }); } @@ -181,7 +194,7 @@ fn update_member() { // Finally, verify we can call LiquidityPools::add_tranche successfully // when given a valid pool + tranche id pair. - let new_member = DomainAddress::EVM(1284, [3; 20]); + let new_member = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [3; 20]); let valid_until = DEFAULT_VALIDITY; // Make ALICE the MembersListAdmin of this Pool @@ -240,7 +253,7 @@ fn update_member() { RuntimeOrigin::signed(ALICE.into()), pool_id, tranche_id, - DomainAddress::EVM(1284, [9; 20]), + DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [9; 20]), valid_until, ), pallet_liquidity_pools::Error::::InvestorDomainAddressNotAMember, @@ -254,17 +267,17 @@ fn update_token_price() { Development::execute_with(|| { setup_pre_requirements(); let decimals: u8 = 15; - - // Now create the pool + let currency_id = AUSD_CURRENCY_ID; let pool_id = DEFAULT_POOL_ID; create_ausd_pool(pool_id); + enable_liquidity_pool_transferability(currency_id); - // Verify it now works assert_ok!(LiquidityPools::update_token_price( - RuntimeOrigin::signed(ALICE.into()), + RuntimeOrigin::signed(BOB.into()), pool_id, default_tranche_id(pool_id), - Domain::EVM(1284), + currency_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), )); }); } @@ -641,3 +654,106 @@ fn schedule_upgrade() { )); }); } + +#[test] +fn cancel_upgrade_upgrade() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + + // Only Root can call `schedule_upgrade` + assert_noop!( + LiquidityPools::cancel_upgrade( + RuntimeOrigin::signed(BOB.into()), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + ), + BadOrigin + ); + + // Need to burn default minted balance from Treasury + OrmlTokens::burn_from( + GLMR_CURRENCY_ID, + &TreasuryAccount::get(), + DEFAULT_BALANCE_GLMR * dollar(18), + ); + + // Failing because the treasury has no funds + assert_noop!( + LiquidityPools::cancel_upgrade(RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, [7; 20]), + pallet_xcm_transactor::Error::::UnableToWithdrawAsset + ); + + // The treasury needs GLRM to cover the fees of sending + // this message + OrmlTokens::deposit( + GLMR_CURRENCY_ID, + &TreasuryAccount::get(), + DEFAULT_BALANCE_GLMR * dollar(18), + ); + + // Now it finally works (even though nothing was scheduled which we don't check + // on the local domain) + assert_ok!(LiquidityPools::cancel_upgrade( + RuntimeOrigin::root(), + MOONBEAM_EVM_CHAIN_ID, + [7; 20] + )); + }); +} + +#[test] +fn update_tranche_token_metadata() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let decimals: u8 = 15; + let pool_id = DEFAULT_POOL_ID; + // NOTE: Default pool admin is BOB + create_ausd_pool(pool_id); + + // Missing tranche token should throw + let nonexistent_tranche = [71u8; 16]; + assert_noop!( + LiquidityPools::update_tranche_token_metadata( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + nonexistent_tranche, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheNotFound + ); + let tranche_id = default_tranche_id(pool_id); + + // Should throw if called by anything but `PoolAdmin` + assert_noop!( + LiquidityPools::update_tranche_token_metadata( + RuntimeOrigin::signed(ALICE.into()), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::NotPoolAdmin + ); + + assert_ok!(LiquidityPools::update_tranche_token_metadata( + RuntimeOrigin::signed(BOB.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!( + LiquidityPools::update_tranche_token_metadata( + RuntimeOrigin::signed(BOB.into()), + pool_id, + tranche_id, + Domain::EVM(MOONBEAM_EVM_CHAIN_ID), + ), + pallet_liquidity_pools::Error::::TrancheMetadataNotFound + ); + }); +} From be60d647103254347619ded266c6b926b2914f85 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 7 Sep 2023 16:00:47 +0200 Subject: [PATCH 78/96] feat: add remaining amounts to Executed* msgs --- libs/traits/src/investments.rs | 2 +- libs/types/src/investments.rs | 21 ++++- pallets/foreign-investments/src/impls/mod.rs | 88 +++++++++++++++++-- .../foreign-investments/src/impls/redeem.rs | 4 +- pallets/foreign-investments/src/lib.rs | 4 +- pallets/investments/src/lib.rs | 2 + pallets/liquidity-pools/src/hooks.rs | 10 ++- pallets/liquidity-pools/src/inbound.rs | 18 ++-- pallets/liquidity-pools/src/lib.rs | 4 +- pallets/liquidity-pools/src/message.rs | 32 +++++++ .../liquidity_pools/foreign_investments.rs | 15 ++-- 11 files changed, 164 insertions(+), 36 deletions(-) diff --git a/libs/traits/src/investments.rs b/libs/traits/src/investments.rs index 52980a57a9..f43091e5fb 100644 --- a/libs/traits/src/investments.rs +++ b/libs/traits/src/investments.rs @@ -356,7 +356,7 @@ pub trait ForeignInvestment { investment_id: Self::InvestmentId, amount: Self::Amount, foreign_payout_currency: Self::CurrencyId, - ) -> Result; + ) -> Result<(Self::Amount, Self::Amount), Self::Error>; /// Collect the results of a user's foreign invest orders for the given /// investment. If any amounts are not fulfilled they are directly diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 3e3148b653..88208fc9a2 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -139,16 +139,22 @@ impl RedeemCollection { /// The collected investment/redemption amount for an account #[derive(Encode, Default, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectedAmount { - /// The amount which was was collected + /// The amount which was collected /// * If investment: Tranche tokens /// * If redemption: Payment currency pub amount_collected: Balance, - /// The amount which invested and converted during processing based on the + /// The amount which was converted during processing based on the /// fulfillment price(s) /// * If investment: Payment currency /// * If redemption: Tranche tokens pub amount_payment: Balance, + + /// The amount which has not been processed as well plus the processed part + /// which has not been claimed yet. + /// * If investment: Payment currency + /// * If redemption: Tranche tokens + pub amount_remaining: Balance, } /// A representation of an investment identifier and the corresponding owner. @@ -225,13 +231,16 @@ impl { +pub struct ExecutedForeignDecreaseInvest { /// The currency in which `DecreaseInvestOrder` was realised pub foreign_currency: Currency, /// The amount of `currency` that was actually executed in the original /// `DecreaseInvestOrder` message, i.e., the amount by which the /// investment order was actually decreased by. pub amount_decreased: Balance, + /// The unprocessed plus processed but not yet collected investment amount + /// denominated in `foreign` payment currency + pub amount_remaining: Balance, } /// A representation of an executed collected investment. @@ -242,6 +251,9 @@ pub struct ExecutedForeignCollectInvest { pub amount_currency_payout: Balance, /// The amount of tranche tokens received for the investment made pub amount_tranche_tokens_payout: Balance, + /// The unprocessed plus processed but not yet collected investment amount + /// denominated in foreign currency + pub amount_remaining_invest: Balance, } /// A representation of an executed collected redemption. @@ -254,4 +266,7 @@ pub struct ExecutedForeignCollectRedeem { pub amount_currency_payout: Balance, /// How many tranche tokens were actually redeemed pub amount_tranche_tokens_payout: Balance, + /// The unprocessed plus processed but not yet collected redemption amount + /// of tranche tokens + pub amount_remaining_redeem: Balance, } diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 7fb13843cb..78af00505b 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -18,7 +18,7 @@ use cfg_traits::{ }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, - ExecutedForeignDecrease, Swap, + ExecutedForeignDecreaseInvest, Swap, }; use frame_support::{ensure, traits::Get, transactional}; use sp_runtime::{ @@ -161,7 +161,7 @@ impl ForeignInvestment for Pallet { investment_id: T::InvestmentId, amount: T::Balance, payout_currency: T::CurrencyId, - ) -> Result { + ) -> Result<(T::Balance, T::Balance), DispatchError> { // TODO(future): This error needs to be communicated to sending domain as it // cannot be resolved by triggering a bot ensure!( @@ -189,7 +189,13 @@ impl ForeignInvestment for Pallet { })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; - Ok(amount) + let remaining_unprocessed_amount = T::Investment::redemption(who, investment_id)?; + let remaining_processed_amount = + CollectedRedemption::::get(who, investment_id).amount_remaining; + let remaining_amount = + remaining_unprocessed_amount.ensure_add(remaining_processed_amount)?; + + Ok((amount, remaining_amount)) } #[transactional] @@ -588,6 +594,7 @@ impl Pallet { ) -> Result>, DispatchError> { let CollectedAmount:: { amount_payment: amount_payment_tranche_tokens, + amount_remaining, .. } = CollectedRedemption::::get(who, investment_id); @@ -603,9 +610,21 @@ impl Pallet { CollectedAmount { amount_collected: done_swap.amount, amount_payment: amount_payment_tranche_tokens, + amount_remaining, }, )?; - CollectedRedemption::::remove(who, investment_id); + CollectedRedemption::::mutate_exists(who, investment_id, |collected| { + // Must only kill if remaining amount exists + match collected { + Some(c) if !c.amount_remaining.is_zero() => { + c.amount_collected = T::Balance::zero(); + c.amount_payment = T::Balance::zero(); + } + _ => { + *collected = None; + } + } + }); Ok(()) } _ => Ok(()), @@ -687,7 +706,7 @@ impl Pallet { investment_id, maybe_redeem_state.unwrap_or_default(), )? - .map(|collected_redeem_state| Some(collected_redeem_state)) + .map(Some) .unwrap_or(maybe_redeem_state) .map(|redeem_state| { RedemptionState::::mutate(who, investment_id, |current_redeem_state| { @@ -990,6 +1009,9 @@ impl Pallet { collected_before .amount_payment .ensure_add_assign(collected.amount_payment)?; + // Remaining amount must not be incremented but overwritten to signal its + // exhaustion + collected_before.amount_remaining = collected.amount_remaining; Ok::<(), DispatchError>(()) })?; @@ -1016,23 +1038,48 @@ impl Pallet { foreign_payout_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result, DispatchError> { - let collected = CollectedInvestment::::take(who, investment_id); + let collected = CollectedInvestment::::mutate_exists(who, investment_id, |collected| { + let collected_before = collected.clone().unwrap_or_default(); + + // Must only kill if remaining amount does not exist + match collected { + Some(c) if !c.amount_remaining.is_zero() => { + c.amount_collected = T::Balance::zero(); + c.amount_payment = T::Balance::zero(); + } + c => { + *c = None; + } + } + + collected_before + }); ensure!( !collected.amount_payment.is_zero(), Error::::InvestError(InvestError::NothingCollected) ); - // Determine payout amount in foreign currency instead of current pool currency - // denomination + // Determine payout and remaining amounts in foreign currency instead of current + // pool currency denomination let amount_currency_payout = T::CurrencyConverter::stable_to_stable( foreign_payout_currency, pool_currency, collected.amount_payment, )?; + let remaining_unprocessed_amount = T::Investment::investment(who, investment_id)?; + let remaining_amount_pool_denominated = collected + .amount_remaining + .ensure_add(remaining_unprocessed_amount)?; + let amount_remaining_invest_foreign_denominated = T::CurrencyConverter::stable_to_stable( + foreign_payout_currency, + pool_currency, + remaining_amount_pool_denominated, + )?; Ok(ExecutedForeignCollectInvest { amount_currency_payout, amount_tranche_tokens_payout: collected.amount_collected, + amount_remaining_invest: amount_remaining_invest_foreign_denominated, }) } @@ -1062,6 +1109,9 @@ impl Pallet { collected_before .amount_payment .ensure_add_assign(collected.amount_payment)?; + // Remaining amount must not be incremented but overwritten to signal its + // exhaustion + collected_before.amount_remaining = collected.amount_remaining; Ok::, DispatchError>(collected_before.clone()) })?; @@ -1105,6 +1155,19 @@ impl Pallet { foreign_currency: T::CurrencyId, amount_decreased: T::Balance, ) -> DispatchResult { + let pool_currency = T::PoolInspect::currency_for(investment_id.of_pool()) + .expect("Pool must exist if decrease was executed; qed."); + let amount_remaining_processed = + CollectedInvestment::::get(who, investment_id).amount_remaining; + let amount_remaining_unprocessed = T::Investment::investment(who, investment_id)?; + let amount_remaining_pool_denominated = + amount_remaining_processed.ensure_add(amount_remaining_unprocessed)?; + let amount_remaining_foreign_denominated = T::CurrencyConverter::stable_to_stable( + foreign_currency, + pool_currency, + amount_remaining_pool_denominated, + )?; + T::DecreasedForeignInvestOrderHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), @@ -1112,9 +1175,10 @@ impl Pallet { // not relevant here last_swap_reason: None, }, - ExecutedForeignDecrease { + ExecutedForeignDecreaseInvest { amount_decreased, foreign_currency, + amount_remaining: amount_remaining_foreign_denominated, }, ) } @@ -1129,6 +1193,11 @@ impl Pallet { currency: T::CurrencyId, collected: CollectedAmount, ) -> DispatchResult { + let remaining_unprocessed_amount = T::Investment::redemption(who, investment_id)?; + let amount_remaining_redeem = collected + .amount_remaining + .ensure_add(remaining_unprocessed_amount)?; + T::CollectedForeignRedemptionHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), @@ -1140,6 +1209,7 @@ impl Pallet { currency, amount_currency_payout: collected.amount_collected, amount_tranche_tokens_payout: collected.amount_payment, + amount_remaining_redeem, }, ) } diff --git a/pallets/foreign-investments/src/impls/redeem.rs b/pallets/foreign-investments/src/impls/redeem.rs index 2d228bbb69..8c7fc9e6d2 100644 --- a/pallets/foreign-investments/src/impls/redeem.rs +++ b/pallets/foreign-investments/src/impls/redeem.rs @@ -548,13 +548,13 @@ where /// Increments the unprocessed redeeming amount or adds `Redeeming*` to the /// state with the provided amount. fn handle_increase(&self, amount: Balance) -> Result { - Self::set_redeem_amount(&self, Self::get_redeeming_amount(&self).ensure_add(amount)?) + Self::set_redeem_amount(self, Self::get_redeeming_amount(self).ensure_add(amount)?) } /// Decrement the unprocessed redeeming amount. I.e., if the state includes /// `Redeeming*`, decreases the redeeming amount. fn handle_decrease(&self, amount: Balance) -> Result { - Self::set_redeem_amount(&self, Self::get_redeeming_amount(&self).ensure_sub(amount)?) + Self::set_redeem_amount(self, Self::get_redeeming_amount(self).ensure_sub(amount)?) } /// Update the state if it includes `ActiveSwapIntoForeignCurrency`. diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 8ee0856a14..32d34fa1f4 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -68,7 +68,7 @@ pub mod pallet { PoolInspect, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ - CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecrease, + CollectedAmount, ExecutedForeignCollectRedeem, ExecutedForeignDecreaseInvest, }; use errors::{InvestError, RedeemError}; use frame_support::{dispatch::HasCompact, pallet_prelude::*}; @@ -199,7 +199,7 @@ pub mod pallet { Self::InvestmentId, (), >, - Status = ExecutedForeignDecrease, + Status = ExecutedForeignDecreaseInvest, Error = DispatchError, >; diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index e412bfe8f2..6978bcd4b5 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -744,6 +744,7 @@ where let collected_investment = CollectedAmount { amount_collected: collection.payout_investment_invest, amount_payment, + amount_remaining: collection.remaining_investment_invest, }; Self::deposit_event(Event::InvestOrdersCollected { @@ -879,6 +880,7 @@ where let collected_redemption = CollectedAmount { amount_collected: collection.payout_investment_redeem, amount_payment, + amount_remaining: collection.remaining_investment_redeem, }; Self::deposit_event(Event::RedeemOrdersCollected { diff --git a/pallets/liquidity-pools/src/hooks.rs b/pallets/liquidity-pools/src/hooks.rs index ff0def4f73..abf123b8b3 100644 --- a/pallets/liquidity-pools/src/hooks.rs +++ b/pallets/liquidity-pools/src/hooks.rs @@ -16,7 +16,7 @@ use cfg_traits::{ }; use cfg_types::{ domain_address::DomainAddress, - investments::{ExecutedForeignDecrease, ForeignInvestmentInfo}, + investments::{ExecutedForeignDecreaseInvest, ForeignInvestmentInfo}, }; use frame_support::{traits::fungibles::Mutate, transactional}; use sp_core::Get; @@ -34,12 +34,12 @@ where { type Error = DispatchError; type Id = ForeignInvestmentInfo; - type Status = ExecutedForeignDecrease; + type Status = ExecutedForeignDecreaseInvest; #[transactional] fn notify_status_change( id: ForeignInvestmentInfo, - status: ExecutedForeignDecrease, + status: ExecutedForeignDecreaseInvest, ) -> DispatchResult { let ForeignInvestmentInfo { id: investment_id, @@ -58,6 +58,7 @@ where investor: investor.into(), currency, currency_payout: status.amount_decreased, + remaining_invest_amount: status.amount_remaining, }; T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; @@ -93,13 +94,14 @@ where T::Tokens::burn_from(status.currency, &investor, status.amount_currency_payout)?; - let message: MessageOf = Message::ExecutedCollectInvest { + let message: MessageOf = Message::ExecutedCollectRedeem { pool_id: investment_id.of_pool(), tranche_id: investment_id.of_tranche(), investor: investor.into(), currency, currency_payout: status.amount_currency_payout, tranche_tokens_payout: status.amount_tranche_tokens_payout, + remaining_redeem_amount: status.amount_remaining_redeem, }; T::OutboundQueue::submit(T::TreasuryAccount::get(), domain_address.domain(), message)?; diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 694fbb52ce..555cd5dbdb 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -234,14 +234,13 @@ where let currency_u128 = currency_index.index; let payout_currency = Self::try_get_payout_currency(invest_id.clone(), currency_index)?; - // TODO(@review): This is exactly `amount` as we can only decrement up to the - // unprocessed redemption - let tranche_tokens_payout = T::ForeignInvestment::decrease_foreign_redemption( - &investor, - invest_id.clone(), - amount, - payout_currency, - )?; + let (tranche_tokens_payout, remaining_redeem_amount) = + T::ForeignInvestment::decrease_foreign_redemption( + &investor, + invest_id.clone(), + amount, + payout_currency, + )?; T::Tokens::transfer( invest_id.into(), @@ -257,6 +256,7 @@ where investor: investor.into(), currency: currency_u128, tranche_tokens_payout, + remaining_redeem_amount, }; T::OutboundQueue::submit(T::TreasuryAccount::get(), destination.domain(), message)?; @@ -316,6 +316,7 @@ where let ExecutedForeignCollectInvest:: { amount_currency_payout, amount_tranche_tokens_payout, + amount_remaining_invest, } = T::ForeignInvestment::collect_foreign_investment( &investor, invest_id.clone(), @@ -338,6 +339,7 @@ where currency: currency_index_u128, currency_payout: amount_currency_payout, tranche_tokens_payout: amount_tranche_tokens_payout, + remaining_invest_amount: amount_remaining_invest, }; T::OutboundQueue::submit(T::TreasuryAccount::get(), destination.domain(), message)?; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index b8d6d2684a..bc0a7a7af7 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -804,7 +804,7 @@ pub mod pallet { ensure!( T::Permission::has( PermissionScope::Pool(pool_id), - who.clone(), + who, Role::PoolRole(PoolRole::PoolAdmin) ), Error::::NotPoolAdmin @@ -983,7 +983,7 @@ pub mod pallet { } => Self::handle_tranche_tokens_transfer( pool_id, tranche_id, - sender.clone(), + sender, receiver.into(), amount, ), diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 590344897c..1620f8384a 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -220,6 +220,10 @@ where /// `DecreaseInvestOrder` message, i.e., the amount by which the /// investment order was actually decreased by. currency_payout: Balance, + /// The remaining investment amount denominated in the `foreign` payment + /// currency. It reflects the sum of the unprocessed as well as the + /// processed but not yet collected amounts. + remaining_invest_amount: Balance, }, /// The message sent back to the domain from which a `DecreaseRedeemOrder` /// message was received, ensuring the correct state update on said domain @@ -239,6 +243,10 @@ where /// original `DecreaseRedeemOrder` message, i.e., the amount by which /// the redeem order was actually decreased by. tranche_tokens_payout: Balance, + /// The remaining redemption amount. It reflects the sum of the + /// unprocessed as well as the processed but not yet collected amount of + /// tranche tokens. + remaining_redeem_amount: Balance, }, /// The message sent back to the domain from which a `CollectInvest` message /// has been received, which will ensure the `investor` gets the payout @@ -258,6 +266,10 @@ where currency_payout: Balance, /// The amount of tranche tokens received for the investment made tranche_tokens_payout: Balance, + /// The remaining investment amount denominated in the `foreign` payment + /// currency. It reflects the sum of the unprocessed as well as the + /// processed but not yet collected amounts. + remaining_invest_amount: Balance, }, /// The message sent back to the domain from which a `CollectRedeem` message /// has been received, which will ensure the `investor` gets the payout @@ -277,6 +289,10 @@ where currency_payout: Balance, /// How many tranche tokens were actually redeemed tranche_tokens_payout: Balance, + /// The remaining redemption amount. It reflects the sum of the + /// unprocessed as well as the processed but not yet collected amount of + /// tranche tokens. + remaining_redeem_amount: Balance, }, /// Cancel an unprocessed invest order for the specified pair of pool and /// tranche token. @@ -597,6 +613,7 @@ impl< investor, currency, currency_payout, + remaining_invest_amount, } => encoded_message( self.call_type(), vec![ @@ -605,6 +622,7 @@ impl< investor.to_vec(), encode_be(currency), encode_be(currency_payout), + encode_be(remaining_invest_amount), ], ), Message::ExecutedDecreaseRedeemOrder { @@ -613,6 +631,7 @@ impl< investor, currency, tranche_tokens_payout, + remaining_redeem_amount, } => encoded_message( self.call_type(), vec![ @@ -621,6 +640,7 @@ impl< investor.to_vec(), encode_be(currency), encode_be(tranche_tokens_payout), + encode_be(remaining_redeem_amount), ], ), Message::ExecutedCollectInvest { @@ -630,6 +650,7 @@ impl< currency, currency_payout, tranche_tokens_payout, + remaining_invest_amount, } => encoded_message( self.call_type(), vec![ @@ -639,6 +660,7 @@ impl< encode_be(currency), encode_be(currency_payout), encode_be(tranche_tokens_payout), + encode_be(remaining_invest_amount), ], ), Message::ExecutedCollectRedeem { @@ -648,6 +670,7 @@ impl< currency, currency_payout, tranche_tokens_payout, + remaining_redeem_amount, } => encoded_message( self.call_type(), vec![ @@ -657,6 +680,7 @@ impl< encode_be(currency), encode_be(currency_payout), encode_be(tranche_tokens_payout), + encode_be(remaining_redeem_amount), ], ), Message::CancelInvestOrder { @@ -813,6 +837,7 @@ impl< investor: decode::<32, _, _>(input)?, currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, + remaining_invest_amount: decode_be_bytes::<16, _, _>(input)?, }), 16 => Ok(Self::ExecutedDecreaseRedeemOrder { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -820,6 +845,7 @@ impl< investor: decode::<32, _, _>(input)?, currency: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, + remaining_redeem_amount: decode_be_bytes::<16, _, _>(input)?, }), 17 => Ok(Self::ExecutedCollectInvest { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -828,6 +854,7 @@ impl< currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, + remaining_invest_amount: decode_be_bytes::<16, _, _>(input)?, }), 18 => Ok(Self::ExecutedCollectRedeem { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -836,6 +863,7 @@ impl< currency: decode_be_bytes::<16, _, _>(input)?, currency_payout: decode_be_bytes::<16, _, _>(input)?, tranche_tokens_payout: decode_be_bytes::<16, _, _>(input)?, + remaining_redeem_amount: decode_be_bytes::<16, _, _>(input)?, }), 19 => Ok(Self::CancelInvestOrder { pool_id: decode_be_bytes::<8, _, _>(input)?, @@ -1214,6 +1242,7 @@ mod tests { investor: vec_to_fixed_array(default_address_20().to_vec()), currency: TOKEN_ID, currency_payout: AMOUNT / 2, + remaining_invest_amount: AMOUNT / 4, }, "0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", ) @@ -1228,6 +1257,7 @@ mod tests { investor: vec_to_fixed_array(default_address_20().to_vec()), currency: TOKEN_ID, tranche_tokens_payout: AMOUNT / 2, + remaining_redeem_amount: AMOUNT / 4, }, "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", ) @@ -1243,6 +1273,7 @@ mod tests { currency: TOKEN_ID, currency_payout: AMOUNT, tranche_tokens_payout: AMOUNT / 2, + remaining_invest_amount: AMOUNT / 4, }, "110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", ) @@ -1258,6 +1289,7 @@ mod tests { currency: TOKEN_ID, currency_payout: AMOUNT, tranche_tokens_payout: AMOUNT / 2, + remaining_redeem_amount: AMOUNT / 4, }, "120000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", ) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 4a35d270c0..6c898f7b41 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -866,10 +866,14 @@ mod same_currencies { )); // Since foreign currency is pool currency, the swap is immediately fulfilled // and ExecutedCollectRedeem dispatched - assert!(!CollectedRedemption::::contains_key( - &investor, - default_investment_id() - ),); + assert_eq!( + CollectedRedemption::::get(&investor, default_investment_id()), + CollectedAmount { + amount_collected: 0, + amount_payment: 0, + amount_remaining: redeem_amount / 2, + } + ); assert_eq!( RedemptionState::::get(&investor, default_investment_id()), RedeemState::Redeeming { @@ -1040,6 +1044,7 @@ mod same_currencies { CollectedAmount { amount_collected: invest_amount / 2 * 4, amount_payment: invest_amount / 2, + amount_remaining: invest_amount / 2, } ); assert_eq!( @@ -1110,6 +1115,7 @@ mod same_currencies { CollectedAmount { amount_collected: invest_amount * 3, amount_payment: invest_amount, + amount_remaining: 0, } ); assert!(!InvestmentState::::contains_key( @@ -1657,7 +1663,6 @@ mod setup { let pool_currency: CurrencyId = PoolSystem::currency_for(pool_id).expect("Pool existence checked already"); - dbg!(pool_currency, currency_id); if currency_id == pool_currency { assert_eq!( InvestmentState::::get(&investor, default_investment_id()), From f7ef147744dced8364990d4610262ffb253b70cb Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 7 Sep 2023 20:34:47 +0200 Subject: [PATCH 79/96] fix: rm remaining from CollectedAmount --- libs/types/src/investments.rs | 6 - pallets/foreign-investments/src/impls/mod.rs | 62 +-- pallets/investments/src/lib.rs | 2 - .../liquidity_pools/foreign_investments.rs | 452 +++++++++--------- 4 files changed, 229 insertions(+), 293 deletions(-) diff --git a/libs/types/src/investments.rs b/libs/types/src/investments.rs index 88208fc9a2..25d6008c50 100644 --- a/libs/types/src/investments.rs +++ b/libs/types/src/investments.rs @@ -149,12 +149,6 @@ pub struct CollectedAmount { /// * If investment: Payment currency /// * If redemption: Tranche tokens pub amount_payment: Balance, - - /// The amount which has not been processed as well plus the processed part - /// which has not been claimed yet. - /// * If investment: Payment currency - /// * If redemption: Tranche tokens - pub amount_remaining: Balance, } /// A representation of an investment identifier and the corresponding owner. diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 78af00505b..5f1204dd83 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -189,11 +189,7 @@ impl ForeignInvestment for Pallet { })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; - let remaining_unprocessed_amount = T::Investment::redemption(who, investment_id)?; - let remaining_processed_amount = - CollectedRedemption::::get(who, investment_id).amount_remaining; - let remaining_amount = - remaining_unprocessed_amount.ensure_add(remaining_processed_amount)?; + let remaining_amount = T::Investment::redemption(who, investment_id)?; Ok((amount, remaining_amount)) } @@ -594,7 +590,6 @@ impl Pallet { ) -> Result>, DispatchError> { let CollectedAmount:: { amount_payment: amount_payment_tranche_tokens, - amount_remaining, .. } = CollectedRedemption::::get(who, investment_id); @@ -610,21 +605,9 @@ impl Pallet { CollectedAmount { amount_collected: done_swap.amount, amount_payment: amount_payment_tranche_tokens, - amount_remaining, }, )?; - CollectedRedemption::::mutate_exists(who, investment_id, |collected| { - // Must only kill if remaining amount exists - match collected { - Some(c) if !c.amount_remaining.is_zero() => { - c.amount_collected = T::Balance::zero(); - c.amount_payment = T::Balance::zero(); - } - _ => { - *collected = None; - } - } - }); + CollectedRedemption::::remove(who, investment_id); Ok(()) } _ => Ok(()), @@ -1009,9 +992,6 @@ impl Pallet { collected_before .amount_payment .ensure_add_assign(collected.amount_payment)?; - // Remaining amount must not be incremented but overwritten to signal its - // exhaustion - collected_before.amount_remaining = collected.amount_remaining; Ok::<(), DispatchError>(()) })?; @@ -1038,22 +1018,7 @@ impl Pallet { foreign_payout_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result, DispatchError> { - let collected = CollectedInvestment::::mutate_exists(who, investment_id, |collected| { - let collected_before = collected.clone().unwrap_or_default(); - - // Must only kill if remaining amount does not exist - match collected { - Some(c) if !c.amount_remaining.is_zero() => { - c.amount_collected = T::Balance::zero(); - c.amount_payment = T::Balance::zero(); - } - c => { - *c = None; - } - } - - collected_before - }); + let collected = CollectedInvestment::::take(who, investment_id); ensure!( !collected.amount_payment.is_zero(), Error::::InvestError(InvestError::NothingCollected) @@ -1066,10 +1031,7 @@ impl Pallet { pool_currency, collected.amount_payment, )?; - let remaining_unprocessed_amount = T::Investment::investment(who, investment_id)?; - let remaining_amount_pool_denominated = collected - .amount_remaining - .ensure_add(remaining_unprocessed_amount)?; + let remaining_amount_pool_denominated = T::Investment::investment(who, investment_id)?; let amount_remaining_invest_foreign_denominated = T::CurrencyConverter::stable_to_stable( foreign_payout_currency, pool_currency, @@ -1109,9 +1071,6 @@ impl Pallet { collected_before .amount_payment .ensure_add_assign(collected.amount_payment)?; - // Remaining amount must not be incremented but overwritten to signal its - // exhaustion - collected_before.amount_remaining = collected.amount_remaining; Ok::, DispatchError>(collected_before.clone()) })?; @@ -1157,11 +1116,7 @@ impl Pallet { ) -> DispatchResult { let pool_currency = T::PoolInspect::currency_for(investment_id.of_pool()) .expect("Pool must exist if decrease was executed; qed."); - let amount_remaining_processed = - CollectedInvestment::::get(who, investment_id).amount_remaining; - let amount_remaining_unprocessed = T::Investment::investment(who, investment_id)?; - let amount_remaining_pool_denominated = - amount_remaining_processed.ensure_add(amount_remaining_unprocessed)?; + let amount_remaining_pool_denominated = T::Investment::investment(who, investment_id)?; let amount_remaining_foreign_denominated = T::CurrencyConverter::stable_to_stable( foreign_currency, pool_currency, @@ -1193,11 +1148,6 @@ impl Pallet { currency: T::CurrencyId, collected: CollectedAmount, ) -> DispatchResult { - let remaining_unprocessed_amount = T::Investment::redemption(who, investment_id)?; - let amount_remaining_redeem = collected - .amount_remaining - .ensure_add(remaining_unprocessed_amount)?; - T::CollectedForeignRedemptionHook::notify_status_change( cfg_types::investments::ForeignInvestmentInfo:: { owner: who.clone(), @@ -1209,7 +1159,7 @@ impl Pallet { currency, amount_currency_payout: collected.amount_collected, amount_tranche_tokens_payout: collected.amount_payment, - amount_remaining_redeem, + amount_remaining_redeem: T::Investment::redemption(who, investment_id)?, }, ) } diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index 6978bcd4b5..e412bfe8f2 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -744,7 +744,6 @@ where let collected_investment = CollectedAmount { amount_collected: collection.payout_investment_invest, amount_payment, - amount_remaining: collection.remaining_investment_invest, }; Self::deposit_event(Event::InvestOrdersCollected { @@ -880,7 +879,6 @@ where let collected_redemption = CollectedAmount { amount_collected: collection.payout_investment_redeem, amount_payment, - amount_remaining: collection.remaining_investment_redeem, }; Self::deposit_event(Event::RedeemOrdersCollected { diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 6c898f7b41..0d6d8cb6bb 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -422,6 +422,225 @@ mod same_currencies { }); } + #[test] + fn partially_collect_investment_for_through_investments() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let invest_amount = 100_000_000; + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let currency_id = AUSD_CURRENCY_ID; + let currency_decimals = currency_decimals::AUSD; + let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); + create_currency_pool(pool_id, currency_id, currency_decimals.into()); + do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); + enable_liquidity_pool_transferability(currency_id); + let investment_currency_id: CurrencyId = default_investment_id().into(); + + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + + // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(50), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + // assert_eq!( + // OrmlTokens::total_issuance(investment_currency_id), + // invest_amount / 8 + // invest_amount + // ); + + // Pre collect assertions + assert!(Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + assert!(!CollectedInvestment::::contains_key( + &investor, + default_investment_id() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { invest_amount } + ); + + // Collecting through Investments should denote amounts and transition + // state + assert_ok!(Investments::collect_investments_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); + + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + // The collected amount is only transferred to the user if they send a + // `CollectInvest` message + assert_eq!( + CollectedInvestment::::get(&investor, default_investment_id()), + CollectedAmount { + amount_collected: invest_amount / 2 * 4, + amount_payment: invest_amount / 2, + } + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: invest_amount / 2 + } + ); + // Tranche Tokens should still be investor's wallet (i.e. not be collected to + // domain) + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &investor), + invest_amount * 2 + ); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + 0 + ); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![0], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: invest_amount * 2, + remaining_investment_invest: invest_amount / 2, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + + // Process rest of investment at 50% rate (1 pool currency = 2 tranche tokens) + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::one(), + price: Rate::checked_from_rational(1, 2).unwrap(), + } + )); + // Order should have been cleared by fulfilling investment + assert_eq!( + pallet_investments::Pallet::::acc_active_invest_order( + default_investment_id(), + ) + .amount, + 0 + ); + assert_eq!( + OrmlTokens::total_issuance(investment_currency_id), + invest_amount * 3 + ); + + // Collect remainder through Investments + assert_ok!(Investments::collect_investments_for( + RuntimeOrigin::signed(ALICE.into()), + investor.clone(), + default_investment_id() + )); + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + assert_eq!( + CollectedInvestment::::get(&investor, default_investment_id()), + CollectedAmount { + amount_collected: invest_amount * 3, + amount_payment: invest_amount, + } + ); + assert!(!InvestmentState::::contains_key( + &investor, + default_investment_id() + )); + // Tranche Tokens should still be investor's wallet (i.e. not be collected to + // domain) + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &investor), + invest_amount * 3 + ); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + 0 + ); + assert!(!System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { + investment_id: default_investment_id(), + who: investor.clone(), + } + .into() + })); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrdersCollected { + investment_id: default_investment_id(), + processed_orders: vec![1], + who: investor.clone(), + collection: InvestCollection:: { + payout_investment_invest: invest_amount, + remaining_investment_invest: 0, + }, + outcome: CollectOutcome::FullyCollected, + } + .into() + })); + // Clearing of foreign InvestState should have been dispatched exactly once + assert_eq!( + System::events() + .iter() + .filter(|e| { + e.event + == pallet_foreign_investments::Event::::ForeignInvestmentCleared { + investor: investor.clone(), + investment_id: default_investment_id(), + } + .into() + }) + .count(), + 1 + ); + + // User collects through foreign investments + let msg = LiquidityPoolMessage::CollectInvest { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + }; + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + assert!(!CollectedInvestment::::contains_key( + &investor, + default_investment_id() + )); + assert_eq!( + OrmlTokens::total_issuance(investment_currency_id), + invest_amount * 3 + ); + assert!(OrmlTokens::free_balance(investment_currency_id, &investor).is_zero()); + assert_eq!( + OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + invest_amount * 3 + ); + }); + } + #[test] fn increase_redeem_order() { TestNet::reset(); @@ -866,14 +1085,10 @@ mod same_currencies { )); // Since foreign currency is pool currency, the swap is immediately fulfilled // and ExecutedCollectRedeem dispatched - assert_eq!( - CollectedRedemption::::get(&investor, default_investment_id()), - CollectedAmount { - amount_collected: 0, - amount_payment: 0, - amount_remaining: redeem_amount / 2, - } - ); + assert!(!CollectedRedemption::::contains_key( + &investor, + default_investment_id() + ),); assert_eq!( RedemptionState::::get(&investor, default_investment_id()), RedeemState::Redeeming { @@ -973,227 +1188,6 @@ mod same_currencies { }); } - #[test] - fn partially_collect_investment_for_through_investments() { - TestNet::reset(); - Development::execute_with(|| { - setup_pre_requirements(); - let pool_id = DEFAULT_POOL_ID; - let invest_amount = 100_000_000; - let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); - let currency_id = AUSD_CURRENCY_ID; - let currency_decimals = currency_decimals::AUSD; - let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); - create_currency_pool(pool_id, currency_id, currency_decimals.into()); - do_initial_increase_investment(pool_id, invest_amount, investor.clone(), currency_id); - enable_liquidity_pool_transferability(currency_id); - let investment_currency_id: CurrencyId = default_investment_id().into(); - - assert!(!Investments::investment_requires_collect( - &investor, - default_investment_id() - )); - - // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche - // tokens - assert_ok!(Investments::process_invest_orders(default_investment_id())); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(1, 4).unwrap(), - } - )); - // assert_eq!( - // OrmlTokens::total_issuance(investment_currency_id), - // invest_amount / 8 - // invest_amount - // ); - - // Pre collect assertions - assert!(Investments::investment_requires_collect( - &investor, - default_investment_id() - )); - assert!(!CollectedInvestment::::contains_key( - &investor, - default_investment_id() - )); - assert_eq!( - InvestmentState::::get(&investor, default_investment_id()), - InvestState::InvestmentOngoing { invest_amount } - ); - - // Collecting through Investments should denote amounts and transition - // state - assert_ok!(Investments::collect_investments_for( - RuntimeOrigin::signed(ALICE.into()), - investor.clone(), - default_investment_id() - )); - - assert!(!Investments::investment_requires_collect( - &investor, - default_investment_id() - )); - // The collected amount is only transferred to the user if they send a - // `CollectInvest` message - assert_eq!( - CollectedInvestment::::get(&investor, default_investment_id()), - CollectedAmount { - amount_collected: invest_amount / 2 * 4, - amount_payment: invest_amount / 2, - amount_remaining: invest_amount / 2, - } - ); - assert_eq!( - InvestmentState::::get(&investor, default_investment_id()), - InvestState::InvestmentOngoing { - invest_amount: invest_amount / 2 - } - ); - // Tranche Tokens should still be investor's wallet (i.e. not be collected to - // domain) - assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &investor), - invest_amount * 2 - ); - assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), - 0 - ); - assert!(System::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![0], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: invest_amount * 2, - remaining_investment_invest: invest_amount / 2, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - - // Process rest of investment at 50% rate (1 pool currency = 2 tranche tokens) - assert_ok!(Investments::process_invest_orders(default_investment_id())); - assert_ok!(Investments::invest_fulfillment( - default_investment_id(), - FulfillmentWithPrice:: { - of_amount: Perquintill::one(), - price: Rate::checked_from_rational(1, 2).unwrap(), - } - )); - // Order should have been cleared by fulfilling investment - assert_eq!( - pallet_investments::Pallet::::acc_active_invest_order( - default_investment_id(), - ) - .amount, - 0 - ); - assert_eq!( - OrmlTokens::total_issuance(investment_currency_id), - invest_amount * 3 - ); - - // Collect remainder through Investments - assert_ok!(Investments::collect_investments_for( - RuntimeOrigin::signed(ALICE.into()), - investor.clone(), - default_investment_id() - )); - assert!(!Investments::investment_requires_collect( - &investor, - default_investment_id() - )); - assert_eq!( - CollectedInvestment::::get(&investor, default_investment_id()), - CollectedAmount { - amount_collected: invest_amount * 3, - amount_payment: invest_amount, - amount_remaining: 0, - } - ); - assert!(!InvestmentState::::contains_key( - &investor, - default_investment_id() - )); - // Tranche Tokens should still be investor's wallet (i.e. not be collected to - // domain) - assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &investor), - invest_amount * 3 - ); - assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), - 0 - ); - assert!(!System::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestCollectedForNonClearedOrderId { - investment_id: default_investment_id(), - who: investor.clone(), - } - .into() - })); - assert!(System::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrdersCollected { - investment_id: default_investment_id(), - processed_orders: vec![1], - who: investor.clone(), - collection: InvestCollection:: { - payout_investment_invest: invest_amount, - remaining_investment_invest: 0, - }, - outcome: CollectOutcome::FullyCollected, - } - .into() - })); - // Clearing of foreign InvestState should have been dispatched exactly once - assert_eq!( - System::events() - .iter() - .filter(|e| { - e.event - == pallet_foreign_investments::Event::::ForeignInvestmentCleared { - investor: investor.clone(), - investment_id: default_investment_id(), - } - .into() - }) - .count(), - 1 - ); - - // User collects through foreign investments - let msg = LiquidityPoolMessage::CollectInvest { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - }; - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); - assert!(!CollectedInvestment::::contains_key( - &investor, - default_investment_id() - )); - assert_eq!( - OrmlTokens::total_issuance(investment_currency_id), - invest_amount * 3 - ); - assert!(OrmlTokens::free_balance(investment_currency_id, &investor).is_zero()); - assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), - invest_amount * 3 - ); - }); - } - mod should_fail { use pallet_foreign_investments::errors::{InvestError, RedeemError}; From 87cdb1a4d9bd192842c2ca27ffcdd2abf7e41615 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 8 Sep 2023 08:09:12 +0200 Subject: [PATCH 80/96] refactor: use Tokens in FI int tests --- .../liquidity_pools/foreign_investments.rs | 124 +++++++++++------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 0d6d8cb6bb..202d5cd888 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -41,12 +41,15 @@ use cfg_types::{ }, }; use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, OrmlTokens, - Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, System, + Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, Permissions, + PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, System, Tokens, }; use frame_support::{ assert_noop, assert_ok, - traits::{fungible::Mutate as _, fungibles::Mutate, Get, PalletInfo}, + traits::{ + fungibles::{Inspect, Mutate, Transfer}, + Get, PalletInfo, + }, }; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use pallet_foreign_investments::{ @@ -176,12 +179,12 @@ mod same_currencies { // Verify investment was decreased into investment account assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), + Tokens::balance(currency_id, &default_investment_account()), final_amount ); // Since the investment was done in the pool currency, the decrement happens // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert_eq!(Tokens::balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::InvestOrderUpdated { investment_id: default_investment_id(), @@ -227,7 +230,7 @@ mod same_currencies { // Verify investment account holds funds before cancelling assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), + Tokens::balance(currency_id, &default_investment_account()), invest_amount ); @@ -264,12 +267,12 @@ mod same_currencies { // Verify investment was entirely drained from investment account assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), + Tokens::balance(currency_id, &default_investment_account()), 0 ); // Since the investment was done in the pool currency, the decrement happens // synchronously and thus it must be burned from investor's holdings - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert_eq!(Tokens::balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == pallet_investments::Event::::InvestOrderUpdated { investment_id: default_investment_id(), @@ -322,7 +325,7 @@ mod same_currencies { assert_ok!(Investments::process_invest_orders(default_investment_id())); // Tranche tokens will be minted upon fulfillment - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), 0); + assert_eq!(Tokens::total_issuance(investment_currency_id), 0); assert_ok!(Investments::invest_fulfillment( default_investment_id(), FulfillmentWithPrice:: { @@ -330,7 +333,7 @@ mod same_currencies { price: Rate::one(), } )); - assert_eq!(OrmlTokens::total_issuance(investment_currency_id), amount); + assert_eq!(Tokens::total_issuance(investment_currency_id), amount); // Mock collection message msg let msg = LiquidityPoolMessage::CollectInvest { @@ -351,7 +354,7 @@ mod same_currencies { // Verify investment was transferred to the domain locator assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + Tokens::balance(default_investment_id().into(), &sending_domain_locator), amount ); @@ -454,11 +457,6 @@ mod same_currencies { price: Rate::checked_from_rational(1, 4).unwrap(), } )); - // assert_eq!( - // OrmlTokens::total_issuance(investment_currency_id), - // invest_amount / 8 - // invest_amount - // ); // Pre collect assertions assert!(Investments::investment_requires_collect( @@ -504,11 +502,11 @@ mod same_currencies { // Tranche Tokens should still be investor's wallet (i.e. not be collected to // domain) assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &investor), + Tokens::balance(investment_currency_id, &investor), invest_amount * 2 ); assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + Tokens::balance(investment_currency_id, &sending_domain_locator), 0 ); assert!(System::events().iter().any(|e| { @@ -544,7 +542,7 @@ mod same_currencies { 0 ); assert_eq!( - OrmlTokens::total_issuance(investment_currency_id), + Tokens::total_issuance(investment_currency_id), invest_amount * 3 ); @@ -572,11 +570,11 @@ mod same_currencies { // Tranche Tokens should still be investor's wallet (i.e. not be collected to // domain) assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &investor), + Tokens::balance(investment_currency_id, &investor), invest_amount * 3 ); assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + Tokens::balance(investment_currency_id, &sending_domain_locator), 0 ); assert!(!System::events().iter().any(|e| { @@ -630,12 +628,12 @@ mod same_currencies { default_investment_id() )); assert_eq!( - OrmlTokens::total_issuance(investment_currency_id), + Tokens::total_issuance(investment_currency_id), invest_amount * 3 ); - assert!(OrmlTokens::free_balance(investment_currency_id, &investor).is_zero()); + assert!(Tokens::balance(investment_currency_id, &investor).is_zero()); assert_eq!( - OrmlTokens::free_balance(investment_currency_id, &sending_domain_locator), + Tokens::balance(investment_currency_id, &sending_domain_locator), invest_amount * 3 ); }); @@ -669,7 +667,7 @@ mod same_currencies { ); // Increasing again should just bump redeeming amount - assert_ok!(OrmlTokens::mint_into( + assert_ok!(Tokens::mint_into( default_investment_id().into(), &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), amount @@ -735,7 +733,7 @@ mod same_currencies { // Verify investment was decreased into investment account assert_eq!( - OrmlTokens::free_balance( + Tokens::balance( default_investment_id().into(), &default_investment_account(), ), @@ -744,11 +742,11 @@ mod same_currencies { // Tokens should have been transferred from investor's wallet to domain's // sovereign account assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), + Tokens::balance(default_investment_id().into(), &investor), 0 ); assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + Tokens::balance(default_investment_id().into(), &sending_domain_locator), decrease_amount ); @@ -825,7 +823,7 @@ mod same_currencies { // Verify investment was decreased into investment account assert_eq!( - OrmlTokens::free_balance( + Tokens::balance( default_investment_id().into(), &default_investment_account(), ), @@ -834,11 +832,11 @@ mod same_currencies { // Tokens should have been transferred from investor's wallet to domain's // sovereign account assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), + Tokens::balance(default_investment_id().into(), &investor), 0 ); assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &sending_domain_locator), + Tokens::balance(default_investment_id().into(), &sending_domain_locator), redeem_amount ); @@ -894,7 +892,7 @@ mod same_currencies { // Fund the pool account with sufficient pool currency, else redemption cannot // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Tokens::mint_into(currency_id, &pool_account, amount)); // Process and fulfill order // NOTE: Without this step, the order id is not cleared and @@ -929,7 +927,7 @@ mod same_currencies { .collect(); // Verify collected redemption was burned from investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert_eq!(Tokens::balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == orml_tokens::Event::::Withdrawn { currency_id, @@ -1024,11 +1022,7 @@ mod same_currencies { // Fund the pool account with sufficient pool currency, else redemption cannot // swap tranche tokens against pool currency - assert_ok!(OrmlTokens::mint_into( - currency_id, - &pool_account, - redeem_amount - )); + assert_ok!(Tokens::mint_into(currency_id, &pool_account, redeem_amount)); assert!(!Investments::redemption_requires_collect( &investor, default_investment_id() @@ -1162,7 +1156,7 @@ mod same_currencies { .into() })); // Verify collected redemption was burned from investor - assert_eq!(OrmlTokens::free_balance(currency_id, &investor), 0); + assert_eq!(Tokens::balance(currency_id, &investor), 0); assert!(System::events().iter().any(|e| e.event == orml_tokens::Event::::Withdrawn { currency_id, @@ -1294,7 +1288,7 @@ mod same_currencies { // Prepare collection let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Tokens::mint_into(currency_id, &pool_account, amount)); assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), @@ -1352,7 +1346,7 @@ mod same_currencies { enable_liquidity_pool_transferability(currency_id); // Mint more into DomainLocator required for subsequent invest attempt - assert_ok!(OrmlTokens::mint_into( + assert_ok!(Tokens::mint_into( default_investment_id().into(), &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), 1, @@ -1361,7 +1355,7 @@ mod same_currencies { // Prepare collection let pool_account = pallet_pool_system::pool_types::PoolLocator { pool_id } .into_account_truncating(); - assert_ok!(OrmlTokens::mint_into(currency_id, &pool_account, amount)); + assert_ok!(Tokens::mint_into(currency_id, &pool_account, amount)); assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), @@ -1454,6 +1448,7 @@ mod mismatching_currencies { .unwrap(); // Should fail to increase to an invalid payment currency + // assert!(!ForeignInvestments::accepted_payment_currency(foreign_currency)); let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { pool_id, tranche_id: default_tranche_id(pool_id), @@ -1466,12 +1461,15 @@ mod mismatching_currencies { pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); + // TODO: Accepted payment currency assertions assert_ok!(OrderBook::add_trading_pair( RuntimeOrigin::root(), pool_currency, foreign_currency, 1 )); + // assert!(ForeignInvestments::accepted_payment_currency(foreign_currency)); + // assert!(ForeignInvestments::accepted_payout_currency(foreign_currency)); assert_ok!(OrderBook::add_trading_pair( RuntimeOrigin::root(), foreign_currency, @@ -1597,7 +1595,31 @@ mod mismatching_currencies { }); } - // TODO: Similar tests for decreasing investments, increase/decrease and + fn invest_with_swaps_happy_path() { + todo!() + } + + fn redeem_with_swaps_happy_path() { + todo!() + } + + fn concurrent_swap_orders_same_direction() { + todo!() + } + + fn concurrent_swap_orders_opposite_direction() { + todo!() + } + + fn fulfill_invest_swap_order_requires_collect() { + todo!() + } + + fn fulfill_redeem_swap_order_requires_collect() { + todo!() + } + + // TODO: Similar tests for decreasing, increase/decrease and // collect redemption } @@ -1647,7 +1669,7 @@ mod setup { )), )); - let amount_before = OrmlTokens::free_balance(currency_id, &default_investment_account()); + let amount_before = Tokens::balance(currency_id, &default_investment_account()); let final_amount = amount_before .ensure_add(amount) .expect("Should not overflow when incrementing amount"); @@ -1678,7 +1700,7 @@ mod setup { } // Verify investment was transferred into investment account assert_eq!( - OrmlTokens::free_balance(currency_id, &default_investment_account()), + Tokens::balance(currency_id, &default_investment_account()), final_amount ); assert!(System::events().iter().any(|e| { @@ -1722,7 +1744,7 @@ mod setup { // Fund `DomainLocator` account of origination domain as redeemed tranche tokens // are transferred from this account instead of minting - assert_ok!(OrmlTokens::mint_into( + assert_ok!(Tokens::mint_into( default_investment_id().into(), &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), amount @@ -1730,14 +1752,14 @@ mod setup { // Verify redemption has not been made yet assert_eq!( - OrmlTokens::free_balance( + Tokens::balance( default_investment_id().into(), &default_investment_account(), ), 0 ); assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), + Tokens::balance(default_investment_id().into(), &investor), 0 ); @@ -1778,18 +1800,18 @@ mod setup { ); // Verify redemption was transferred into investment account assert_eq!( - OrmlTokens::free_balance( + Tokens::balance( default_investment_id().into(), &default_investment_account(), ), amount ); assert_eq!( - OrmlTokens::free_balance(default_investment_id().into(), &investor), + Tokens::balance(default_investment_id().into(), &investor), 0 ); assert_eq!( - OrmlTokens::free_balance( + Tokens::balance( default_investment_id().into(), &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) ), From b10fe79a9aed8da9deac72ffef10a80cc61f717e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 12:11:55 +0200 Subject: [PATCH 81/96] fix: concurrent swaps, misc --- Cargo.lock | 1 + libs/traits/src/lib.rs | 4 + pallets/foreign-investments/src/hooks.rs | 171 ++- .../foreign-investments/src/impls/invest.rs | 380 ++++--- pallets/foreign-investments/src/impls/mod.rs | 348 +++--- pallets/foreign-investments/src/lib.rs | 8 +- pallets/foreign-investments/src/types.rs | 2 +- pallets/liquidity-pools/src/lib.rs | 4 - pallets/order-book/src/lib.rs | 13 +- pallets/order-book/src/tests.rs | 24 + runtime/integration-tests/Cargo.toml | 3 + .../liquidity_pools/foreign_investments.rs | 999 +++++++++++++++--- 12 files changed, 1442 insertions(+), 515 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f079087d64..2efb6d4b34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11086,6 +11086,7 @@ dependencies = [ "pallet-liquidity-pools", "pallet-liquidity-pools-gateway", "pallet-loans", + "pallet-order-book", "pallet-permissions", "pallet-pool-registry", "pallet-pool-system", diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index f2ef364910..35d6b48777 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -474,6 +474,7 @@ pub trait TokenSwaps { type Balance; type SellRatio; type OrderId; + type OrderDetails; /// Swap tokens buying a `buy_amount` of `currency_in` using the /// `currency_out` tokens. The implementer of this method should know @@ -566,6 +567,9 @@ pub trait TokenSwaps { /// Check if the order is still active. fn is_active(order: Self::OrderId) -> bool; + + /// Retrieve the details of the order if it exists. + fn get_order_details(order: Self::OrderId) -> Option; } /// Trait to transmit a change of status for anything uniquely identifiable. diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 4909ffe603..ec203687e5 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -16,8 +16,11 @@ use cfg_traits::{ StatusNotificationHook, }; use cfg_types::investments::{CollectedAmount, ForeignInvestmentInfo}; -use frame_support::transactional; -use sp_runtime::{DispatchError, DispatchResult}; +use frame_support::{ensure, transactional}; +use sp_runtime::{ + traits::{EnsureAdd, EnsureSub, Zero}, + DispatchError, DispatchResult, +}; use sp_std::marker::PhantomData; use crate::{ @@ -47,67 +50,121 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { status: SwapOf, ) -> Result<(), DispatchError> { let maybe_info = ForeignInvestmentInfoStorage::::get(id); - if maybe_info.is_none() { return Ok(()); } - let info = maybe_info.expect("Cannot be None"); - - let reason = info - .last_swap_reason - .ok_or(Error::::TokenSwapReasonNotFound)?; - - match reason { - TokenSwapReason::Investment => { - // If the investment requires to be collected, the transition of the - // `InvestState` would fail. By implicitly collecting here, we defend against - // that and ensure that the swap order fulfillment won't be reverted (since this - // function is `transactional`). - - // NOTE: We only collect the tranche tokens, but do not transfer them back. This - // updates the unprocessed investment amount such that transitioning the - // `InvestState` is not blocked. The user still has to do that manually by - // sending `CollectInvest`. - if T::Investment::investment_requires_collect(&info.owner, info.id) { - T::Investment::collect_investment(info.owner.clone(), info.id)?; - } - - let pre_state = InvestmentState::::get(&info.owner, info.id); - let post_state = pre_state - .transition(InvestTransition::FulfillSwapOrder(status)) - .map_err(|e| { - // Inner error holds finer granularity but should never occur - log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(InvestError::FulfillSwapOrder) - })?; - Pallet::::apply_invest_state_transition(&info.owner, info.id, post_state) + let info = maybe_info.expect("Cannot be None; qed"); + + match info.last_swap_reason { + // Swapping into pool or foreign + Some(TokenSwapReason::Investment) => { + Self::fulfill_invest_swap_order(&info.owner, info.id, status, true) + } + // Swapping into foreign + Some(TokenSwapReason::Redemption) => { + Self::fulfill_redeem_swap_order(&info.owner, info.id, status) } - TokenSwapReason::Redemption => { - // If the investment requires to be collected, the transition of the - // `RedeemState` would fail. By implicitly collecting here, we defend against - // that and ensure that the swap order fulfillment won't be reverted (since this - // function is `transactional`). - - // NOTE: We only collect the pool currency, but do neither transfer them to the - // investor nor initiate the swap back into foreign currency. This updates the - // unprocessed investment amount such that transitioning the `RedeemState` is - // not blocked. The user still has to do that manually by - // sending `CollectInvest`. - if T::Investment::redemption_requires_collect(&info.owner, info.id) { - T::Investment::collect_redemption(info.owner.clone(), info.id)?; - } - - let pre_state = RedemptionState::::get(&info.owner, info.id); - let post_state = pre_state - .transition(RedeemTransition::FulfillSwapOrder(status)) - .map_err(|e| { - // Inner error holds finer granularity but should never occur - log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(RedeemError::FulfillSwapOrder) - })?; - Pallet::::apply_redeem_state_transition(&info.owner, info.id, post_state) + // Both states are swapping into foreign + Some(TokenSwapReason::InvestmentAndRedemption) => { + let active_invest_swap_amount = InvestmentState::::get(&info.owner, info.id) + .get_active_swap_amount_foreign_denominated()?; + let active_redeem_swap_amount = InvestmentState::::get(&info.owner, info.id) + .get_active_swap() + .map(|swap| swap.amount) + .unwrap_or(T::Balance::zero()); + + ensure!( + status.amount + <= active_invest_swap_amount.ensure_add(active_redeem_swap_amount)?, + DispatchError::Arithmetic(sp_runtime::ArithmeticError::Overflow) + ); + + let invest_swap = SwapOf:: { + amount: active_invest_swap_amount, + ..status + }; + let redeem_swap = SwapOf:: { + amount: status.amount.ensure_sub(active_invest_swap_amount)?, + ..status + }; + + // NOTE: Fulfillment of invest swap before redeem one for no particular reason + Self::fulfill_invest_swap_order(&info.owner, info.id, invest_swap, false)?; + Self::fulfill_redeem_swap_order(&info.owner, info.id, redeem_swap) } + _ => { + log::debug!("Fulfilled token swap order id {:?} without advancing foreign investment because swap reason does not exist", id); + Ok(()) + } + } + } +} + +impl FulfilledSwapOrderHook { + fn fulfill_invest_swap_order( + who: &T::AccountId, + investment_id: T::InvestmentId, + swap: SwapOf, + update_swap_order: bool, + ) -> DispatchResult { + // If the investment requires to be collected, the transition of the + // `InvestState` would fail. By implicitly collecting here, we defend against + // that and ensure that the swap order fulfillment won't be reverted (since this + // function is `transactional`). + // + // NOTE: We only collect the tranche tokens, but do not transfer them back. This + // updates the unprocessed investment amount such that transitioning the + // `InvestState` is not blocked. The user still has to do that manually by + // sending `CollectInvest`. + if T::Investment::investment_requires_collect(who, investment_id) { + T::Investment::collect_investment(who.clone(), investment_id)?; + } + + let pre_state = InvestmentState::::get(who, investment_id); + let post_state = pre_state + .transition(InvestTransition::FulfillSwapOrder(swap)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(InvestError::FulfillSwapOrder) + })?; + Pallet::::apply_invest_state_transition( + who, + investment_id, + post_state, + update_swap_order, + ) + } + + fn fulfill_redeem_swap_order( + who: &T::AccountId, + investment_id: T::InvestmentId, + swap: SwapOf, + ) -> DispatchResult { + // If the investment requires to be collected, the transition of the + // `RedeemState` would fail. By implicitly collecting here, we defend against + // that and ensure that the swap order fulfillment won't be reverted (since this + // function is `transactional`). + // + // NOTE: We only collect the pool currency, but do neither transfer them to the + // investor nor initiate the swap back into foreign currency. This updates the + // unprocessed investment amount such that transitioning the `RedeemState` is + // not blocked. The user still has to do that manually by + // sending `CollectInvest`. + if T::Investment::redemption_requires_collect(who, investment_id) { + T::Investment::collect_redemption(who.clone(), investment_id)?; } + + // Check if redeem state is swapping and thus needs to be fulfilled + let pre_state = RedemptionState::::get(who, investment_id); + let post_state = pre_state + .transition(RedeemTransition::FulfillSwapOrder(swap)) + .map_err(|e| { + // Inner error holds finer granularity but should never occur + log::debug!("ForeignInvestment state transition error: {:?}", e); + Error::::from(RedeemError::FulfillSwapOrder) + })?; + Pallet::::apply_redeem_state_transition(who, investment_id, post_state) } } diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index dc8106b776..3e74f63dcd 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -51,6 +51,30 @@ where } } + // TODO: Docs + pub(crate) fn get_active_swap(&self) -> Option> { + match *self { + Self::NoState => None, + Self::InvestmentOngoing { .. } => None, + Self::ActiveSwapIntoPoolCurrency { swap } => Some(swap), + Self::ActiveSwapIntoForeignCurrency { swap } => Some(swap), + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Some(swap), + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Some(swap), + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Some(swap), + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Some(swap), + Self::SwapIntoForeignDone { .. } => None, + Self::SwapIntoForeignDoneAndInvestmentOngoing { .. } => None, + } + } + /// Returns the potentially existing active swap amount denominated in pool /// currency: /// * If the state includes `ActiveSwapIntoPoolCurrency`, it returns @@ -62,22 +86,46 @@ where &self, ) -> Result { match *self { - InvestState::NoState => Ok(T::Balance::zero()), - InvestState::InvestmentOngoing { .. } => Ok(T::Balance::zero()), - InvestState::ActiveSwapIntoPoolCurrency { swap } => Ok(swap.amount), - InvestState::ActiveSwapIntoForeignCurrency { swap } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(swap.amount), - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { - Ok(swap.amount) - }, - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { - Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?) - }, - InvestState::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), - InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), + Self::NoState => Ok(T::Balance::zero()), + Self::InvestmentOngoing { .. } => Ok(T::Balance::zero()), + Self::ActiveSwapIntoPoolCurrency { swap } => Ok(swap.amount), + Self::ActiveSwapIntoForeignCurrency { swap } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(swap.amount), + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Ok(swap.amount), + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?), + Self::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), + Self::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), } } @@ -92,35 +140,67 @@ where &self, ) -> Result { match *self { - InvestState::NoState => Ok(T::Balance::zero()), - InvestState::InvestmentOngoing { .. } => Ok(T::Balance::zero()), - InvestState::ActiveSwapIntoPoolCurrency { swap } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoForeignCurrency { swap } => Ok(swap.amount), - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?), - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => Ok(swap.amount), - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { - Ok(T::CurrencyConverter::stable_to_stable(swap.currency_out, swap.currency_in, swap.amount)?) - }, - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap, .. } => { + Self::NoState => Ok(T::Balance::zero()), + Self::InvestmentOngoing { .. } => Ok(T::Balance::zero()), + Self::ActiveSwapIntoPoolCurrency { swap } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoForeignCurrency { swap } => Ok(swap.amount), + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap, .. } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap, .. } => Ok(swap.amount), + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap, .. } => { + Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?) + } + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap, .. } => { Ok(swap.amount) - }, - InvestState::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), - InvestState::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), + } + Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Ok(T::CurrencyConverter::stable_to_stable( + swap.currency_out, + swap.currency_in, + swap.amount, + )?), + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + swap, + .. + } => Ok(swap.amount), + Self::SwapIntoForeignDone { .. } => Ok(T::Balance::zero()), + Self::SwapIntoForeignDoneAndInvestmentOngoing { .. } => Ok(T::Balance::zero()), } } /// Returns the `invest_amount` if existent, else zero. pub(crate) fn get_investing_amount(&self) -> T::Balance { match *self { - InvestState::InvestmentOngoing { invest_amount} | - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } | - InvestState::SwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, - _ => T::Balance::zero() + Self::InvestmentOngoing { invest_amount } + | Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { invest_amount, .. } + | Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { invest_amount, .. } + | Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + invest_amount, + .. + } + | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + invest_amount, + .. + } + | Self::SwapIntoForeignDoneAndInvestmentOngoing { invest_amount, .. } => invest_amount, + _ => T::Balance::zero(), } } } @@ -489,14 +569,15 @@ where } match &self { - // Cannot reduce if there is neither an ongoing investment nor an active swap into pool currency - InvestState::NoState - | InvestState::ActiveSwapIntoForeignCurrency { .. } - | InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { .. } => { - Err(DispatchError::Other("Invalid invest state when transitioning a decrease")) - }, + // Cannot reduce if there is neither an ongoing investment nor an active swap into pool + // currency + Self::NoState + | Self::ActiveSwapIntoForeignCurrency { .. } + | Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { .. } => Err(DispatchError::Other( + "Invalid invest state when transitioning a decrease", + )), // Increment foreign swap amount up to ongoing investment - InvestState::InvestmentOngoing { invest_amount } => { + Self::InvestmentOngoing { invest_amount } => { let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( swap.currency_out, swap.currency_in, @@ -504,23 +585,17 @@ where )?; match foreign_amount_pool_denominated.cmp(invest_amount) { - Ordering::Less => { - Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap, - invest_amount: invest_amount.ensure_sub(foreign_amount_pool_denominated)?, - }) - }, - Ordering::Equal => { - Ok(Self::ActiveSwapIntoForeignCurrency { swap }) - } + Ordering::Less => Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap, + invest_amount: invest_amount.ensure_sub(foreign_amount_pool_denominated)?, + }), + Ordering::Equal => Ok(Self::ActiveSwapIntoForeignCurrency { swap }), // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) - } + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Underflow)), } - }, + } // Increment return done amount up to amount of the active pool swap - InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Self::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, false)?; let foreign_amount_pool_denominated = T::CurrencyConverter::stable_to_stable( @@ -530,26 +605,23 @@ where )?; match foreign_amount_pool_denominated.cmp(&pool_swap.amount) { - Ordering::Less => { - Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { - swap: Swap { - amount: pool_swap.amount.ensure_sub(foreign_amount_pool_denominated)?, - ..*pool_swap - }, - done_amount: swap.amount, - }) - } - Ordering::Equal => { - Ok(Self::SwapIntoForeignDone { done_swap: swap }) - }, + Ordering::Less => Ok(Self::ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { + swap: Swap { + amount: pool_swap + .amount + .ensure_sub(foreign_amount_pool_denominated)?, + ..*pool_swap + }, + done_amount: swap.amount, + }), + Ordering::Equal => Ok(Self::SwapIntoForeignDone { done_swap: swap }), // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) - } + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Underflow)), } - }, - // Increment `foreign_done` up to pool swap amount and increment foreign swap amount up to ongoing investment - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + } + // Increment `foreign_done` up to pool swap amount and increment foreign swap amount up + // to ongoing investment + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { swap: pool_swap, invest_amount, } => { @@ -565,7 +637,8 @@ where swap.currency_out, pool_swap.amount, )?; - let max_decrease_amount_pool_denominated = pool_swap.amount.ensure_add(*invest_amount)?; + let max_decrease_amount_pool_denominated = + pool_swap.amount.ensure_add(*invest_amount)?; // Decrease swap into pool if foreign_amount_pool_denominated < pool_swap.amount { @@ -615,9 +688,9 @@ where else { Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } - }, + } // Increment foreign swap up to ongoing investment - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: foreign_swap, invest_amount, } => { @@ -631,24 +704,18 @@ where )?; match swap_amount_pool_denominated.cmp(invest_amount) { - Ordering::Less => { - Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { - swap: Swap { amount, ..swap }, - invest_amount: invest_amount.ensure_sub(swap_amount_pool_denominated)?, - }) - }, - Ordering::Equal => { - Ok(Self::ActiveSwapIntoForeignCurrency { - swap: Swap { amount, ..swap }, - }) - }, + Ordering::Less => Ok(Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + swap: Swap { amount, ..swap }, + invest_amount: invest_amount.ensure_sub(swap_amount_pool_denominated)?, + }), + Ordering::Equal => Ok(Self::ActiveSwapIntoForeignCurrency { + swap: Swap { amount, ..swap }, + }), // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) - }, + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Underflow)), } - }, - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + } + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: foreign_swap, done_amount, invest_amount, @@ -683,7 +750,7 @@ where Err(DispatchError::Arithmetic(ArithmeticError::Underflow)) } } - }, + } _ => Err(DispatchError::Other( "Invalid invest state, should automatically be transitioned into \ ActiveSwapIntoPoolCurrencyAndInvestmentOngoing", @@ -721,41 +788,54 @@ where swap: Swap, ) -> Result { match &self { - InvestState::NoState | InvestState::InvestmentOngoing { .. } => Err(DispatchError::Other( + Self::NoState | Self::InvestmentOngoing { .. } => Err(DispatchError::Other( "Invalid invest state when transitioning a fulfilled order", )), - // Increment ongoing investment by swapped amount - InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { + Self::ActiveSwapIntoPoolCurrency { swap: pool_swap } => { swap.ensure_currencies_match(pool_swap, true)?; - match swap.amount.cmp(&pool_swap.amount) { - Ordering::Equal => { - Ok(Self::InvestmentOngoing { - invest_amount: swap.amount, - }) - }, - Ordering::Less => { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: pool_swap.amount.ensure_sub(swap.amount)?, - ..swap - }, - invest_amount: swap.amount, - }) - } + Ordering::Equal => Ok(Self::InvestmentOngoing { + invest_amount: swap.amount, + }), + Ordering::Less => Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: pool_swap.amount.ensure_sub(swap.amount)?, + ..swap + }, + invest_amount: swap.amount, + }), // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), + } + } + // Increment ongoing investment by swapped amount + Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: pool_swap, + invest_amount, + } => { + swap.ensure_currencies_match(pool_swap, true)?; + let invest_amount = invest_amount.ensure_add(swap.amount)?; + match swap.amount.cmp(&pool_swap.amount) { + Ordering::Equal => Ok(Self::InvestmentOngoing { invest_amount }), + Ordering::Less => Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: pool_swap.amount.ensure_sub(swap.amount)?, + ..swap + }, + invest_amount, + }), + // should never occur but let's be safe here + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), } }, // Increment done_foreign by swapped amount - InvestState::ActiveSwapIntoForeignCurrency { swap: foreign_swap } => { + Self::ActiveSwapIntoForeignCurrency { swap: foreign_swap } => { swap.ensure_currencies_match(foreign_swap, true)?; match swap.amount.cmp(&foreign_swap.amount) { - Ordering::Equal => { + // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign + Ordering::Equal | Ordering::Greater => { Ok(Self::SwapIntoForeignDone { done_swap: swap }) } Ordering::Less => { @@ -767,48 +847,18 @@ where done_amount: swap.amount, }) } - // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } - } - }, - // Increment ongoing investment by swapped amount - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: pool_swap, - invest_amount, - } => { - swap.ensure_currencies_match(pool_swap, true)?; - let invest_amount = invest_amount.ensure_add(swap.amount)?; - - match swap.amount.cmp(&pool_swap.amount) { - Ordering::Equal => { - Ok(Self::InvestmentOngoing { invest_amount }) - }, - Ordering::Less => { - Ok(Self::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: pool_swap.amount.ensure_sub(swap.amount)?, - ..swap - }, - invest_amount, - }) - } - // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } } }, // Increment done_foreign by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: foreign_swap, invest_amount, } => { swap.ensure_currencies_match(foreign_swap, true)?; match swap.amount.cmp(&foreign_swap.amount) { - Ordering::Equal => { + // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign + Ordering::Equal | Ordering::Greater => { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount: *invest_amount, @@ -826,14 +876,10 @@ where }, ) } - // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } } }, // Increment done_foreign by swapped amount - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { swap: foreign_swap, done_amount, } => { @@ -841,7 +887,8 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; match swap.amount.cmp(&foreign_swap.amount) { - Ordering::Equal => { + // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign + Ordering::Equal | Ordering::Greater => { Ok(Self::SwapIntoForeignDone { done_swap: Swap { amount: done_amount, @@ -858,14 +905,10 @@ where done_amount, }) } - // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } } }, // Increment done_foreign by swapped amount, leave invest amount untouched - InvestState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { + Self::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: foreign_swap, done_amount, invest_amount, @@ -874,7 +917,8 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; match swap.amount.cmp(&foreign_swap.amount) { - Ordering::Equal => { + // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign + Ordering::Equal | Ordering::Greater => { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, @@ -895,10 +939,6 @@ where }, ) } - // should never occur but let's be safe here - Ordering::Greater => { - Err(DispatchError::Arithmetic(ArithmeticError::Overflow)) - } } }, _ => Err(DispatchError::Other( @@ -970,7 +1010,7 @@ where ) -> Result { if let Self::InvestmentOngoing { invest_amount } = &self { if swap.amount < *invest_amount { - Ok(InvestState::SwapIntoForeignDoneAndInvestmentOngoing { + Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount: invest_amount.ensure_sub(swap.amount)?, }) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 5f1204dd83..3dc53ad03f 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -72,7 +72,7 @@ impl ForeignInvestment for Pallet { log::debug!("InvestState transition error: {:?}", e); Error::::from(InvestError::Increase) })?; - Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; + Pallet::::apply_invest_state_transition(who, investment_id, post_state, true)?; Ok(()) } @@ -108,7 +108,7 @@ impl ForeignInvestment for Pallet { log::debug!("InvestState transition error: {:?}", e); Error::::from(InvestError::Decrease) })?; - Pallet::::apply_invest_state_transition(who, investment_id, post_state)?; + Pallet::::apply_invest_state_transition(who, investment_id, post_state, true)?; Ok(()) } @@ -328,6 +328,7 @@ impl Pallet { who: &T::AccountId, investment_id: T::InvestmentId, state: InvestState, + update_swap_order: bool, ) -> DispatchResult { // Must not send executed decrease notification before updating redemption let mut maybe_executed_decrease: Option<(T::CurrencyId, T::Balance)> = None; @@ -398,14 +399,16 @@ impl Pallet { T::Investment::update_investment(who, investment_id, invest_amount)?; } - let (maybe_invest_state_prio, maybe_new_redeem_state) = Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment)?; - // Dispatch transition event, post swap state has priority if it exists as it was the last transition - if let Some(invest_state_prio) = maybe_invest_state_prio { - Self::deposit_investment_event(who, investment_id, Some(invest_state_prio)); + // No need to handle swap order, if redeem state transition is applied afterwards + let final_invest_state = if update_swap_order { + Self::handle_swap_order(who, investment_id, maybe_swap, TokenSwapReason::Investment).map(|(maybe_invest_state, maybe_redeem_state)| { + Self::deposit_redemption_event(who, investment_id, maybe_redeem_state); + maybe_invest_state.unwrap_or(invest_state) + })? } else { - Self::deposit_investment_event(who, investment_id, Some(invest_state)); - } - Self::deposit_redemption_event(who, investment_id, maybe_new_redeem_state); + invest_state + }; + Self::deposit_investment_event(who, investment_id, Some(final_invest_state)); // Send notification after updating invest as else funds are still locked in investment account if let Some((foreign_currency, decreased_amount)) = maybe_executed_decrease { @@ -658,32 +661,35 @@ impl Pallet { DispatchError, > { // check for concurrent conflicting swap orders - if let Some(swap_order_id) = TokenSwapOrderIds::::get(who, investment_id) { - let (maybe_updated_swap, maybe_invest_state, maybe_redeem_state) = - Self::handle_concurrent_swap_orders(who, investment_id, swap_order_id, reason)?; + if TokenSwapOrderIds::::get(who, investment_id).is_some() { + let (maybe_updated_swap, maybe_invest_state, maybe_redeem_state, swap_reason) = + Self::handle_concurrent_swap_orders(who, investment_id)?; // Update or kill swap order with updated order having priority in case it was // overwritten if let Some(swap_order) = maybe_updated_swap { - Self::place_swap_order(who, investment_id, swap_order, reason)?; - } else if let Some(swap_order) = maybe_swap { - Self::place_swap_order(who, investment_id, swap_order, reason)?; + Self::place_swap_order(who, investment_id, swap_order, swap_reason)?; } else { Self::kill_swap_order(who, investment_id)?; } - // Update invest and redeem states if necessary - InvestmentState::::mutate(who, investment_id, |current_invest_state| { - // Should never occur but let's be safe - if let Some(state) = &maybe_invest_state { - *current_invest_state = state.clone(); + // Update invest state and kill if NoState + InvestmentState::::mutate_exists(who, investment_id, |current_invest_state| { + match &maybe_invest_state { + Some(state) if state != &InvestState::NoState => { + *current_invest_state = Some(state.clone()); + } + Some(state) if state == &InvestState::NoState => { + *current_invest_state = None; + } + _ => (), } }); // Need to check if `SwapReturnDone` is part of state without // `ActiveSwapIntoForeignCurrency` as this implies the successful termination of // a collect (with swap into foreign currency). If this is the case, the - // returned redeem state needs to be updated as well. + // returned redeem state needs to be updated or killed as well. let returning_redeem_state = Self::apply_collect_redeem_transition( who, investment_id, @@ -692,8 +698,12 @@ impl Pallet { .map(Some) .unwrap_or(maybe_redeem_state) .map(|redeem_state| { - RedemptionState::::mutate(who, investment_id, |current_redeem_state| { - *current_redeem_state = redeem_state; + RedemptionState::::mutate_exists(who, investment_id, |current_redeem_state| { + if redeem_state != RedeemState::NoState { + *current_redeem_state = Some(redeem_state); + } else { + *current_redeem_state = None; + } }); redeem_state }); @@ -702,7 +712,7 @@ impl Pallet { } // Update to provided value, if not none else if let Some(swap_order) = maybe_swap { - Self::place_swap_order(who, investment_id, swap_order, reason)?; + Self::place_swap_order(who, investment_id, swap_order, Some(reason))?; Ok((None, None)) } else { Ok((None, None)) @@ -715,7 +725,9 @@ impl Pallet { /// NOTE: Must only be called in `handle_swap_order`. fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { - T::TokenSwaps::cancel_order(swap_order_id)?; + if T::TokenSwaps::is_active(swap_order_id) { + T::TokenSwaps::cancel_order(swap_order_id)?; + } ForeignInvestmentInfo::::remove(swap_order_id); } Ok(()) @@ -730,14 +742,38 @@ impl Pallet { who: &T::AccountId, investment_id: T::InvestmentId, swap: SwapOf, - reason: TokenSwapReason, + reason: Option, ) -> DispatchResult { - // exit early if swap.amount.is_zero() { return Self::kill_swap_order(who, investment_id); } - match TokenSwapOrderIds::::get(who, investment_id) { - Some(swap_order_id) if T::TokenSwaps::is_active(swap_order_id) => { + + // Determine whether swap order direction changed which would require the order + // to be cancelled and all associated storage to be killed + let maybe_swap_order_id = TokenSwapOrderIds::::get(who, investment_id); + let cancel_swap_order = maybe_swap_order_id + .map(|swap_order_id| { + let cancel_swap_order = T::TokenSwaps::get_order_details(swap_order_id) + .map(|swap_order| { + swap_order.currency_in != swap.currency_in + || swap_order.currency_out != swap.currency_out + }) + .unwrap_or(false); + + if cancel_swap_order { + Self::kill_swap_order(who, investment_id)?; + } + + Ok::(cancel_swap_order) + }) + .transpose()? + .unwrap_or(false); + + match maybe_swap_order_id { + // Swap order is active and matches the swap direction + Some(swap_order_id) + if T::TokenSwaps::is_active(swap_order_id) && !cancel_swap_order => + { T::TokenSwaps::update_order( who.clone(), swap_order_id, @@ -752,10 +788,11 @@ impl Pallet { ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, - last_swap_reason: Some(reason), + last_swap_reason: reason, }, ); } + // Swap order either has not existed at all or was just cancelled _ => { let swap_order_id = T::TokenSwaps::place_order( who.clone(), @@ -773,7 +810,7 @@ impl Pallet { ForeignInvestmentInfoOf:: { owner: who.clone(), id: investment_id, - last_swap_reason: Some(reason), + last_swap_reason: reason, }, ); } @@ -812,30 +849,41 @@ impl Pallet { fn handle_concurrent_swap_orders( who: &T::AccountId, investment_id: T::InvestmentId, - swap_order_id: T::TokenSwapOrderId, - reason: TokenSwapReason, ) -> Result< ( Option>, Option>, Option>, + Option, ), DispatchError, > { - let last_reason = ForeignInvestmentInfo::::get(swap_order_id) - .ok_or(Error::::InvestmentInfoNotFound)? - .last_swap_reason - .ok_or(Error::::TokenSwapReasonNotFound)?; - - // Exit early if both reasons match, i.e. we would not override any opposite - // swap order - if last_reason == reason { - return Ok((None, None, None)); - } - // Read states from storage and determine amounts in possible denominations let invest_state = InvestmentState::::get(who, investment_id); let redeem_state = RedemptionState::::get(who, investment_id); + let active_invest_swap = invest_state.get_active_swap(); + let active_redeem_swap = redeem_state.get_active_swap(); + + // Exit early if neither or only a single swap is active such that no merging is + // necessary + if active_invest_swap.is_none() && active_redeem_swap.is_none() { + return Ok((None, None, None, None)); + } else if active_invest_swap.is_none() { + return Ok(( + active_redeem_swap, + None, + Some(redeem_state), + Some(TokenSwapReason::Redemption), + )); + } else if active_redeem_swap.is_none() { + return Ok(( + active_invest_swap, + Some(invest_state), + None, + Some(TokenSwapReason::Investment), + )); + } + let invest_swap_amount_pool_deno = invest_state.get_active_swap_amount_pool_denominated()?; let invest_swap_amount_foreign_deno = @@ -865,113 +913,109 @@ impl Pallet { .max(redeem_swap_amount_foreign_deno) .ensure_sub(invest_swap_amount_foreign_deno.min(redeem_swap_amount_foreign_deno))?; - // Determine new invest state - let new_invest_state = match invest_state { - // As redeem swap can only be into foreign currency, we need to delta on the opposite - // swap directions - InvestState::ActiveSwapIntoPoolCurrency { swap } => { - if invest_swap_amount_pool_deno > redeem_swap_amount_pool_deno { - Some( - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: swap_amount_opposite_direction_pool_deno, - ..swap - }, - invest_amount: resolved_amount_pool_deno, - }, - ) - } else { - Some(InvestState::InvestmentOngoing { - invest_amount: resolved_amount_pool_deno, - }) + let (maybe_token_swap, maybe_new_invest_state, maybe_new_redeem_state, swap_reason) = + match (active_invest_swap, active_redeem_swap) { + // same swap direction + (Some(invest_swap), Some(redeem_swap)) + if invest_swap.currency_in == redeem_swap.currency_in => + { + invest_swap.ensure_currencies_match(&redeem_swap, true)?; + let token_swap = Swap { + amount: invest_swap.amount.ensure_add(redeem_swap.amount)?, + ..invest_swap + }; + Ok(( + Some(token_swap), + None, + None, + Some(TokenSwapReason::InvestmentAndRedemption), + )) } - } - // Same as above except for the base investment amount which is incremented - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: invest_swap, - invest_amount, - } => { - if invest_swap_amount_pool_deno > redeem_swap_amount_pool_deno { - Some( - InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { - swap: Swap { - amount: swap_amount_opposite_direction_pool_deno, - ..invest_swap - }, - invest_amount: invest_amount.ensure_add(resolved_amount_pool_deno)?, - }, - ) - } else { - Some(InvestState::InvestmentOngoing { - invest_amount: invest_amount.ensure_add(resolved_amount_pool_deno)?, - }) + // opposite swap direction + (Some(invest_swap), Some(redeem_swap)) + if invest_swap.currency_in == redeem_swap.currency_out => + { + invest_swap.ensure_currencies_match(&redeem_swap, false)?; + let new_redeem_state = redeem_state.fulfill_active_swap_amount( + redeem_swap_amount_foreign_deno.min(invest_swap_amount_foreign_deno), + )?; + + let new_invest_state = match invest_state.clone() { + InvestState::ActiveSwapIntoPoolCurrency { swap: pool_swap } + | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: pool_swap, + .. + } => { + let new_pool_swap = Swap { + amount: pool_swap.amount.ensure_sub(resolved_amount_pool_deno)?, + ..pool_swap + }; + let new_invest_amount = invest_state + .get_investing_amount() + .ensure_add(resolved_amount_pool_deno)?; + + if pool_swap.amount == resolved_amount_pool_deno { + Ok(InvestState::InvestmentOngoing { + invest_amount: new_invest_amount, + }) + } else { + Ok( + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + invest_amount: new_invest_amount, + swap: new_pool_swap, + }, + ) + } + } + state => Ok(state), + } + .map_err(|e: DispatchError| e)?; + + if invest_swap_amount_foreign_deno > redeem_swap_amount_foreign_deno { + let swap = Swap { + amount: swap_amount_opposite_direction_pool_deno, + ..invest_swap + }; + Ok(( + Some(swap), + Some(new_invest_state), + Some(new_redeem_state), + Some(TokenSwapReason::Investment), + )) + } else { + let swap = Swap { + amount: swap_amount_opposite_direction_foreign_deno, + ..redeem_swap + }; + Ok(( + Some(swap), + Some(new_invest_state), + Some(new_redeem_state), + Some(TokenSwapReason::Redemption), + )) + } } + _ => Err(DispatchError::Other( + "Uncaught short circuit when merging concurrent swap orders", + )), } - // We must not alter the invest state if there is no active pool currency swap - _ => None, - }; - - // Determine final swap amount and new redeem state - let (final_swap_amount_foreign_deno, new_redeem_state) = match invest_state { - // Opposite swaps cancel out at least one (or if equal amounts) both swaps - InvestState::ActiveSwapIntoPoolCurrency { .. } - | InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { .. } => { - let new_state = redeem_state - .fulfill_active_swap_amount( - redeem_swap_amount_foreign_deno - .min(swap_amount_opposite_direction_foreign_deno), - ) - .unwrap_or(redeem_state); - - Ok((swap_amount_opposite_direction_foreign_deno, new_state)) - } - // All leftover combinations either do not involve any active swaps or both - // swaps have the same direction, i.e. into foreign currency. Thus, we can - // leave states untouched and just add up the potential swap amount. - _ => Ok(( - invest_swap_amount_foreign_deno.ensure_add(redeem_swap_amount_foreign_deno)?, - redeem_state, - )), - } - .map(|(token_swap_amount_foreign_deno, maybe_new_redeem_state)| { - // If old state match new state, no need to return it as this could cause a - // follow-up transition trigger - if redeem_state == maybe_new_redeem_state { - (token_swap_amount_foreign_deno, None) - } else { - (token_swap_amount_foreign_deno, Some(maybe_new_redeem_state)) - } - }) - .map_err(|e: DispatchError| e)?; - - // Determine token swap from amount - let token_swap = redeem_state - .get_active_swap() - .map(|swap| { - if invest_swap_amount_foreign_deno > redeem_swap_amount_foreign_deno { - Ok(Swap { - amount: T::CurrencyConverter::stable_to_stable( - swap.currency_out, - swap.currency_in, - final_swap_amount_foreign_deno, - )?, - currency_in: swap.currency_out, - currency_out: swap.currency_in, - }) - } - // handle redeem_swap_amount >= invest_swap_amount as well as all cases, in which - // neither states include an active swap - else { - Ok(Swap { - amount: final_swap_amount_foreign_deno, - ..swap - }) - } - }) - .transpose() .map_err(|e: DispatchError| e)?; - Ok((token_swap, new_invest_state, new_redeem_state)) + let new_invest_state = match maybe_new_invest_state { + Some(state) if state == invest_state => None, + state => state, + }; + let new_redeem_state = match maybe_new_redeem_state { + Some(state) if state == redeem_state => None, + state => state, + }; + + Ok(( + maybe_token_swap, + new_invest_state, + new_redeem_state, + swap_reason, + )) } /// Increments the collected investment amount and transitions investment @@ -1000,7 +1044,7 @@ impl Pallet { let pre_state = InvestmentState::::get(who, investment_id); let post_state = pre_state.transition(InvestTransition::CollectInvestment(investing_amount))?; - Self::apply_invest_state_transition(who, investment_id, post_state).map_err(|e| { + Self::apply_invest_state_transition(who, investment_id, post_state, true).map_err(|e| { log::debug!("InvestState transition error: {:?}", e); Error::::from(InvestError::Collect) })?; @@ -1064,14 +1108,12 @@ impl Pallet { .expect("Impossible to collect redemption for non existing pool at this point"); // Increment by previously stored amounts (via `CollectedInvestmentHook`) - let collected = CollectedRedemption::::mutate(who, investment_id, |collected_before| { - collected_before - .amount_collected + CollectedRedemption::::mutate(who, investment_id, |old| { + old.amount_collected .ensure_add_assign(collected.amount_collected)?; - collected_before - .amount_payment + old.amount_payment .ensure_add_assign(collected.amount_payment)?; - Ok::, DispatchError>(collected_before.clone()) + Ok::<(), DispatchError>(()) })?; // Transition state to initiate swap from pool to foreign currency diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 32d34fa1f4..b6793428e4 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -189,6 +189,7 @@ pub mod pallet { CurrencyId = Self::CurrencyId, Balance = Self::Balance, OrderId = Self::TokenSwapOrderId, + OrderDetails = Swap, SellRatio = Self::Rate, >; @@ -276,13 +277,14 @@ pub mod pallet { ValueQuery, >; - /// Maps `TokenSwapOrders` to `ForeignInvestmentInfo` to implicitly enable - /// mapping to `InvestmentState` and `RedemptionState`. + /// Maps a token swap order id to the corresponding `ForeignInvestmentInfo` + /// to implicitly enable mapping to `InvestmentState` and `RedemptionState`. /// /// NOTE: The storage is immediately killed when the swap order is /// completely fulfilled even if the corresponding investment and/or /// redemption might not be fully processed. #[pallet::storage] + #[pallet::getter(fn foreign_investment_info)] pub(super) type ForeignInvestmentInfo = StorageMap<_, Blake2_128Concat, T::TokenSwapOrderId, ForeignInvestmentInfoOf>; @@ -293,6 +295,7 @@ pub mod pallet { /// completely fulfilled even if the investment might not be fully /// processed. #[pallet::storage] + #[pallet::getter(fn token_swap_order_ids)] pub(super) type TokenSwapOrderIds = StorageDoubleMap< _, Blake2_128Concat, @@ -382,7 +385,6 @@ pub mod pallet { #[pallet::error] pub enum Error { - InvalidInvestmentCurrency, /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. InvestmentInfoNotFound, diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 73adaab924..9fc39dc0fd 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -28,6 +28,7 @@ use crate::Config; pub enum TokenSwapReason { Investment, Redemption, + InvestmentAndRedemption, } /// Restriction of `pallet_foreign_investments::Config` trait to support @@ -351,4 +352,3 @@ pub enum RedeemTransition< FulfillSwapOrder(Swap), CollectRedemption(Balance, Swap), } - diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index bc0a7a7af7..8525bbdeef 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -812,10 +812,6 @@ pub mod pallet { let investment_id = Self::derive_invest_id(pool_id, tranche_id)?; let metadata = T::AssetRegistry::metadata(&investment_id.into()) .ok_or(Error::::TrancheMetadataNotFound)?; - #[cfg(feature = "std")] - { - dbg!(&metadata); - } let token_name = vec_to_fixed_array(metadata.name); let token_symbol = vec_to_fixed_array(metadata.symbol); diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index c11fb29282..fc5fee96df 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -461,7 +461,7 @@ pub mod pallet { order_id, placing_account: order.placing_account, fulfilling_account: account_id, - partial_fulfillment: true, + partial_fulfillment: false, currency_in: order.asset_in_id, currency_out: order.asset_out_id, fulfillment_amount: order.buy_amount, @@ -613,6 +613,7 @@ pub mod pallet { { type Balance = T::Balance; type CurrencyId = T::AssetCurrencyId; + type OrderDetails = Swap; type OrderId = T::OrderIdNonce; type SellRatio = T::SellRatio; @@ -813,6 +814,16 @@ pub mod pallet { >::contains_key(order) } + fn get_order_details(order: Self::OrderId) -> Option> { + Orders::::get(order) + .map(|order| Swap { + amount: order.buy_amount, + currency_in: order.asset_in_id, + currency_out: order.asset_out_id, + }) + .ok() + } + fn valid_pair(currency_in: Self::CurrencyId, currency_out: Self::CurrencyId) -> bool { TradingPair::::get(currency_in, currency_out).is_ok() } diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index e6d1ec52ed..e9c7d10356 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -1001,6 +1001,30 @@ fn update_order_requires_non_zero_price() { }) } +#[test] +fn get_order_details_works() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_eq!( + OrderBook::get_order_details(order_id), + Some(cfg_types::investments::Swap { + amount: 15 * CURRENCY_AUSD_DECIMALS, + currency_in: DEV_AUSD_CURRENCY_ID, + currency_out: DEV_USDT_CURRENCY_ID + }) + ); + assert!(OrderBook::get_order_details(order_id + 1).is_none()); + }); +} + pub fn get_account_orders( account_id: ::AccountId, ) -> Result::OrderIdNonce, OrderOf)>, Error> diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index fab211410d..818fd98c7f 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -101,6 +101,7 @@ pallet-investments = { path = "../../pallets/investments" } pallet-liquidity-pools = { path = "../../pallets/liquidity-pools" } pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway" } pallet-loans = { path = "../../pallets/loans" } +pallet-order-book = { path = "../../pallets/order-book" } pallet-permissions = { path = "../../pallets/permissions" } pallet-pool-registry = { path = "../../pallets/pool-registry" } pallet-pool-system = { path = "../../pallets/pool-system" } @@ -139,6 +140,7 @@ std = [ "pallet-balances/std", "pallet-foreign-investments/std", "pallet-investments/std", + "pallet-order-book/std", "pallet-transaction-payment/std", "pallet-uniques/std", "pallet-xcm/std", @@ -186,6 +188,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-foreign-investments/runtime-benchmarks", "pallet-investments/runtime-benchmarks", + "pallet-order-book/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain/runtime-benchmarks", diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 202d5cd888..e519003f22 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -26,7 +26,7 @@ use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, use cfg_traits::{ investments::{Investment, OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::InboundQueue, - PoolInspect, + PoolInspect, SimpleCurrencyConversion, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, @@ -42,7 +42,7 @@ use cfg_types::{ }; use development_runtime::{ Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, Permissions, - PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, System, Tokens, + PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, StableToStableRate, System, Tokens, }; use frame_support::{ assert_noop, assert_ok, @@ -57,7 +57,9 @@ use pallet_foreign_investments::{ CollectedRedemption, InvestmentState, RedemptionState, }; use pallet_investments::CollectOutcome; -use runtime_common::account_conversion::AccountConverter; +use runtime_common::{ + account_conversion::AccountConverter, foreign_investments::SimpleStableCurrencyConverter, +}; use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, BoundedVec, DispatchError, FixedPointNumber, Perquintill, SaturatedConversion, WeakBoundedVec, @@ -1401,15 +1403,14 @@ mod same_currencies { } mod mismatching_currencies { - use cfg_traits::SimpleCurrencyConversion; - use cfg_types::investments::Swap; - use development_runtime::{DefaultTokenSellRate, OrderBook, StableToStableRate}; - use pallet_foreign_investments::InvestmentState; - use runtime_common::foreign_investments::SimpleStableCurrencyConverter; + use cfg_traits::investments::ForeignInvestment; + use cfg_types::investments::{ForeignInvestmentInfo, Swap}; + use development_runtime::{DefaultTokenSellRate, OrderBook}; + use pallet_foreign_investments::{types::TokenSwapReason, InvestmentState}; use super::*; use crate::{ - liquidity_pools::pallet::development::tests::register_usdt, + liquidity_pools::pallet::development::{setup::CHARLIE, tests::register_usdt}, utils::{GLMR_CURRENCY_ID, USDT_CURRENCY_ID}, }; @@ -1448,7 +1449,10 @@ mod mismatching_currencies { .unwrap(); // Should fail to increase to an invalid payment currency - // assert!(!ForeignInvestments::accepted_payment_currency(foreign_currency)); + assert!(!ForeignInvestments::accepted_payment_currency( + default_investment_id(), + foreign_currency + )); let increase_msg = LiquidityPoolMessage::IncreaseInvestOrder { pool_id, tranche_id: default_tranche_id(pool_id), @@ -1461,21 +1465,30 @@ mod mismatching_currencies { pallet_liquidity_pools::Error::::InvalidPaymentCurrency ); - // TODO: Accepted payment currency assertions assert_ok!(OrderBook::add_trading_pair( RuntimeOrigin::root(), pool_currency, foreign_currency, 1 )); - // assert!(ForeignInvestments::accepted_payment_currency(foreign_currency)); - // assert!(ForeignInvestments::accepted_payout_currency(foreign_currency)); + assert!(ForeignInvestments::accepted_payment_currency( + default_investment_id(), + foreign_currency + )); + assert!(!ForeignInvestments::accepted_payout_currency( + default_investment_id(), + foreign_currency + )); assert_ok!(OrderBook::add_trading_pair( RuntimeOrigin::root(), foreign_currency, pool_currency, 1 )); + assert!(ForeignInvestments::accepted_payout_currency( + default_investment_id(), + foreign_currency + )); // Should be able to invest since InvestmentState does not have an active swap, // i.e. any tradable pair is allowed to invest at this point @@ -1595,134 +1608,868 @@ mod mismatching_currencies { }); } - fn invest_with_swaps_happy_path() { - todo!() - } - - fn redeem_with_swaps_happy_path() { - todo!() - } - - fn concurrent_swap_orders_same_direction() { - todo!() - } - - fn concurrent_swap_orders_opposite_direction() { - todo!() - } - - fn fulfill_invest_swap_order_requires_collect() { - todo!() - } - - fn fulfill_redeem_swap_order_requires_collect() { - todo!() - } - - // TODO: Similar tests for decreasing, increase/decrease and - // collect redemption -} - -mod setup { - use super::*; - use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; - - /// Sets up required permissions for the investor and executes an - /// initial investment via LiquidityPools by executing - /// `IncreaseInvestOrder`. + #[test] + /// Propagate swaps only via OrderBook fulfillments. /// - /// Assumes `setup_pre_requirements` and - /// `investments::create_currency_pool` to have been called - /// beforehand - pub fn do_initial_increase_investment( - pool_id: u64, - amount: Balance, - investor: AccountId, - currency_id: CurrencyId, - ) { - let valid_until = DEFAULT_VALIDITY; - - // Mock incoming increase invest message - let msg = LiquidityPoolMessage::IncreaseInvestOrder { - pool_id, - tranche_id: default_tranche_id(pool_id), - investor: investor.clone().into(), - currency: general_currency_index(currency_id), - amount, - }; - - // Should fail if investor does not have investor role yet - assert_noop!( - LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), - DispatchError::Other("Account does not have the TrancheInvestor permission.") - ); - - // Make investor the MembersListAdmin of this Pool - assert_ok!(Permissions::add( - RuntimeOrigin::root(), - Role::PoolRole(PoolRole::PoolAdmin), - investor.clone(), - PermissionScope::Pool(pool_id), - Role::PoolRole(PoolRole::TrancheInvestor( - default_tranche_id(pool_id), - valid_until - )), - )); + /// Flow: Increase, fulfill, decrease, fulfill + fn invest_swaps_happy_path() { + TestNet::reset(); + Development::execute_with(|| { + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let trader: AccountId = ALICE.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10_000_000_000_000_000; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); - let amount_before = Tokens::balance(currency_id, &default_investment_account()); - let final_amount = amount_before - .ensure_add(amount) - .expect("Should not overflow when incrementing amount"); + // USDT investment preparations + register_usdt(); + // Overwrite multilocation to enable LP transferability + enable_liquidity_pool_transferability(foreign_currency); + assert_ok!(Tokens::mint_into( + pool_currency, + &trader, + invest_amount_pool_denominated + )); + let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + pool_currency, + foreign_currency, + 1 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + foreign_currency, + pool_currency, + 1 + )); - // Execute byte message - assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + // Increase such that active swap into USDT is initialized + do_initial_increase_investment( + pool_id, + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, + ); + let swap_order_id = + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .expect("Swap order id created during increase"); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id), + Some(ForeignInvestmentInfo { + owner: investor.clone(), + id: default_investment_id(), + last_swap_reason: Some(TokenSwapReason::Investment) + }) + ); - let pool_currency: CurrencyId = - PoolSystem::currency_for(pool_id).expect("Pool existence checked already"); - if currency_id == pool_currency { + // Fulfilling order should propagate it from `ActiveSwapIntoForeignCurrency` to + // `InvestmentOngoing`. + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: invest_amount_pool_denominated, + currency_in: pool_currency, + currency_out: foreign_currency, + sell_rate_limit: Rate::one(), + } + .into() + })); assert_eq!( InvestmentState::::get(&investor, default_investment_id()), InvestState::InvestmentOngoing { - invest_amount: amount + invest_amount: invest_amount_pool_denominated } ); - } else { + assert!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .is_none() + ); + assert!(ForeignInvestments::foreign_investment_info(swap_order_id).is_none()); + + // Decrease by half the investment amount + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated / 2, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); assert_eq!( InvestmentState::::get(&investor, default_investment_id()), - InvestState::ActiveSwapIntoPoolCurrency { + InvestState::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { swap: Swap { - currency_in: pool_currency, - currency_out: currency_id, - amount - } + amount: invest_amount_foreign_denominated / 2, + currency_in: foreign_currency, + currency_out: pool_currency, + }, + invest_amount: invest_amount_pool_denominated / 2, } ); - } - // Verify investment was transferred into investment account - assert_eq!( - Tokens::balance(currency_id, &default_investment_account()), - final_amount - ); - assert!(System::events().iter().any(|e| { - e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { - investor: investor.clone(), - investment_id: default_investment_id(), - state: InvestState::InvestmentOngoing { - invest_amount: final_amount - }, - } - .into() - })); - assert!(System::events().iter().any(|e| { - e.event - == pallet_investments::Event::::InvestOrderUpdated { - investment_id: default_investment_id(), - submitted_at: 0, - who: investor.clone(), - amount: final_amount, + let swap_order_id = + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .expect("Swap order id created during decrease"); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id), + Some(ForeignInvestmentInfo { + owner: investor.clone(), + id: default_investment_id(), + last_swap_reason: Some(TokenSwapReason::Investment) + }) + ); + + // Fulfill the decrease swap order + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: invest_amount_foreign_denominated / 2, + currency_in: foreign_currency, + currency_out: pool_currency, + sell_rate_limit: Rate::one(), + } + .into() + })); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated / 2 } - .into() - })); + ); + assert!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .is_none() + ); + assert!(ForeignInvestments::foreign_investment_info(swap_order_id).is_none()); + + // TODO: Check for event that ExecutedDecreaseInvestOrder was + // dispatched + }); + } + + fn redeem_with_swaps_happy_path() { + // increase + // process + // fulfill swap order + todo!() + } + + #[test] + /// Verify handling concurrent swap orders works if + /// * Invest is swapping from pool to foreign after decreasing an + /// unprocessed investment + /// * Redeem is swapping from pool to foreign after collecting + fn concurrent_swap_orders_same_direction() { + TestNet::reset(); + Development::execute_with(|| { + // Increase invest setup + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let trader: AccountId = ALICE.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10_000_000_000_000_000; + let swap_order_id = 1; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + // invest in pool currency to reach `InvestmentOngoing` quickly + do_initial_increase_investment( + pool_id, + invest_amount_pool_denominated, + investor.clone(), + pool_currency, + ); + + // USDT setup + register_usdt(); + enable_liquidity_pool_transferability(foreign_currency); + let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); + assert_ok!(Tokens::mint_into( + foreign_currency, + &trader, + invest_amount_foreign_denominated * 2 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + pool_currency, + foreign_currency, + 1 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + foreign_currency, + pool_currency, + 1 + )); + + // Decrease invest setup to have invest order swapping into foreign currency + let msg = LiquidityPoolMessage::DecreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); + + // Redeem setup: Increase and process + assert_ok!(Tokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + invest_amount_pool_denominated + )); + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_pool_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + assert_ok!(Tokens::mint_into( + pool_currency, + &pool_account, + invest_amount_pool_denominated + )); + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + // Process 50% of redemption at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(50), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::Investment + ); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::InvestmentAndRedemption + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoForeignCurrency { + swap: Swap { + amount: invest_amount_foreign_denominated, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount: invest_amount_pool_denominated / 2, + swap: Swap { + amount: invest_amount_foreign_denominated / 8, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + let swap_amount = + invest_amount_foreign_denominated + invest_amount_foreign_denominated / 8; + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderUpdated { + order_id: swap_order_id, + account: investor.clone(), + buy_amount: swap_amount, + sell_rate_limit: Rate::one(), + min_fulfillment_amount: swap_amount, + } + .into() + })); + + // Process remaining redemption at 25% rate, i.e. 1 pool currency = + // 4 tranche tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(100), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoForeignCurrency { + swap: Swap { + amount: invest_amount_foreign_denominated, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::ActiveSwapIntoForeignCurrency { + swap: Swap { + amount: invest_amount_foreign_denominated / 4, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + let swap_amount = + invest_amount_foreign_denominated + invest_amount_foreign_denominated / 4; + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderUpdated { + order_id: swap_order_id, + account: investor.clone(), + buy_amount: swap_amount, + sell_rate_limit: Rate::one(), + min_fulfillment_amount: swap_amount, + } + .into() + })); + + // Fulfilling order should kill both the invest as well as redeem state + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: invest_amount_foreign_denominated / 4 * 5, + currency_in: foreign_currency, + currency_out: pool_currency, + sell_rate_limit: Rate::one(), + } + .into() + })); + assert!(!InvestmentState::::contains_key( + &investor, + default_investment_id() + )); + assert!(!RedemptionState::::contains_key( + &investor, + default_investment_id() + )); + assert!(ForeignInvestments::foreign_investment_info(swap_order_id).is_none()); + assert!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .is_none() + ); + }); + } + + // increase invest --> swap into pool + // + // increase redeem + // process redemption --> swap into foreign + #[test] + /// Verify handling concurrent swap orders works if + /// * Invest is swapping from foreign to pool after increasing + /// * Redeem is swapping from pool to foreign after collecting + fn concurrent_swap_orders_opposite_direction() { + TestNet::reset(); + Development::execute_with(|| { + // Increase invest setup + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = + AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let trader: AccountId = ALICE.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10_000_000_000_000_000; + let swap_order_id = 1; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + + // USDT setup + register_usdt(); + enable_liquidity_pool_transferability(foreign_currency); + let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); + assert_ok!(Tokens::mint_into( + foreign_currency, + &trader, + invest_amount_foreign_denominated * 2 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + pool_currency, + foreign_currency, + 1 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + foreign_currency, + pool_currency, + 1 + )); + + // Increase invest setup to have invest order swapping into pool currency + do_initial_increase_investment( + pool_id, + invest_amount_foreign_denominated, + investor.clone(), + foreign_currency, + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrency { + swap: Swap { + amount: invest_amount_pool_denominated, + currency_in: pool_currency, + currency_out: foreign_currency + } + }, + ); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::Investment + ); + assert_eq!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()), + Some(swap_order_id) + ); + + // Redeem setup: Increase and process + assert_ok!(Tokens::mint_into( + default_investment_id().into(), + &Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()), + 3 * invest_amount_pool_denominated + )); + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + assert_ok!(Tokens::mint_into( + pool_currency, + &pool_account, + 3 * invest_amount_pool_denominated + )); + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_pool_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::Investment + ); + assert_eq!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()), + Some(swap_order_id) + ); + + // Process 50% of redemption at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(50), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::Investment + ); + assert_eq!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()), + Some(swap_order_id) + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + invest_amount: invest_amount_pool_denominated / 8, + swap: Swap { + amount: invest_amount_pool_denominated / 8 * 7, + currency_in: pool_currency, + currency_out: foreign_currency + } + }, + ); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::Redeeming { + redeem_amount: invest_amount_pool_denominated / 2, + } + ); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderUpdated { + order_id: swap_order_id, + account: investor.clone(), + buy_amount: invest_amount_pool_denominated / 8 * 7, + sell_rate_limit: Rate::one(), + min_fulfillment_amount: invest_amount_pool_denominated / 8 * 7, + } + .into() + })); + + // TODO: Check redemption consumes investment instead + // Process remaining redemption at 25% rate, i.e. 1 pool currency = + // 4 tranche tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(100), + price: Rate::checked_from_rational(1, 4).unwrap(), + } + )); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + invest_amount: invest_amount_pool_denominated / 4, + swap: Swap { + amount: invest_amount_pool_denominated / 4 * 3, + currency_in: pool_currency, + currency_out: foreign_currency + } + } + ); + assert!(!RedemptionState::::contains_key( + &investor, + default_investment_id() + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderUpdated { + order_id: swap_order_id, + account: investor.clone(), + buy_amount: invest_amount_pool_denominated / 4 * 3, + sell_rate_limit: Rate::one(), + min_fulfillment_amount: invest_amount_pool_denominated / 4 * 3, + } + .into() + })); + + // Redeem again + let msg = LiquidityPoolMessage::IncreaseRedeemOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_pool_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); + // Process remaining redemption at 200% rate, i.e. 1 tranche token = 2 pool + // currency + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice:: { + of_amount: Perquintill::from_percent(100), + price: Rate::checked_from_rational(2, 1).unwrap(), + } + )); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert!(ForeignInvestments::foreign_investment_info(swap_order_id).is_none()); + // Swap order id should be bumped since swap order update occurred for opposite + // direction (from foreign->pool to foreign->pool) + let swap_order_id = 2; + assert_eq!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()), + Some(swap_order_id) + ); + assert_eq!( + ForeignInvestments::foreign_investment_info(swap_order_id) + .unwrap() + .last_swap_reason + .unwrap(), + TokenSwapReason::Redemption + ); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated + } + ); + let remaining_foreign_swap_amount = + 2 * invest_amount_foreign_denominated - invest_amount_foreign_denominated / 4 * 3; + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + done_amount: invest_amount_foreign_denominated / 4 * 3, + swap: Swap { + amount: remaining_foreign_swap_amount, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + + // Fulfilling order should the invest + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(System::events().iter().any(|e| { + e.event + == pallet_order_book::Event::::OrderFulfillment { + order_id: swap_order_id, + placing_account: investor.clone(), + fulfilling_account: trader.clone(), + partial_fulfillment: false, + fulfillment_amount: remaining_foreign_swap_amount, + currency_in: foreign_currency, + currency_out: pool_currency, + sell_rate_limit: Rate::one(), + } + .into() + })); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated + } + ); + assert!(ForeignInvestments::foreign_investment_info(swap_order_id).is_none()); + assert!( + ForeignInvestments::token_swap_order_ids(&investor, default_investment_id()) + .is_none() + ); + }); + } + + fn fulfill_invest_swap_order_requires_collect() { + todo!() + // increase initial invest in pool currency + // increase invest in foreign + // process invest + // fulfill swap order + } + + fn fulfill_redeem_swap_order_requires_collect() { + // increase initial redeem + // process redemption + // collect partial + // collect partial + // fulfill swap order + todo!() + } +} + +mod setup { + use super::*; + use crate::liquidity_pools::pallet::development::tests::liquidity_pools::setup::DEFAULT_OTHER_DOMAIN_ADDRESS; + + /// Sets up required permissions for the investor and executes an + /// initial investment via LiquidityPools by executing + /// `IncreaseInvestOrder`. + /// + /// Assumes `setup_pre_requirements` and + /// `investments::create_currency_pool` to have been called + /// beforehand + pub fn do_initial_increase_investment( + pool_id: u64, + amount: Balance, + investor: AccountId, + currency_id: CurrencyId, + ) { + let valid_until = DEFAULT_VALIDITY; + let pool_currency: CurrencyId = + PoolSystem::currency_for(pool_id).expect("Pool existence checked already"); + + // Mock incoming increase invest message + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(currency_id), + amount, + }; + + // Should fail if investor does not have investor role yet + // However, failure is async for foreign currencies as part of updating the + // investment after the swap was fulfilled + if currency_id == pool_currency { + assert_noop!( + LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg.clone()), + DispatchError::Other("Account does not have the TrancheInvestor permission.") + ); + } + + // Make investor the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + investor.clone(), + PermissionScope::Pool(pool_id), + Role::PoolRole(PoolRole::TrancheInvestor( + default_tranche_id(pool_id), + valid_until + )), + )); + + let amount_before = Tokens::balance(currency_id, &default_investment_account()); + let final_amount = amount_before + .ensure_add(amount) + .expect("Should not overflow when incrementing amount"); + + // Execute byte message + assert_ok!(LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg)); + + if currency_id == pool_currency { + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: amount + } + ); + // Verify investment was transferred into investment account + assert_eq!( + Tokens::balance(currency_id, &default_investment_account()), + final_amount + ); + assert!(System::events().iter().any(|e| { + e.event == pallet_foreign_investments::Event::::ForeignInvestmentUpdated { + investor: investor.clone(), + investment_id: default_investment_id(), + state: InvestState::InvestmentOngoing { + invest_amount: final_amount + }, + } + .into() + })); + assert!(System::events().iter().any(|e| { + e.event + == pallet_investments::Event::::InvestOrderUpdated { + investment_id: default_investment_id(), + submitted_at: 0, + who: investor.clone(), + amount: final_amount, + } + .into() + })); + } else { + let amount_pool_denominated: u128 = SimpleStableCurrencyConverter::< + OrmlAssetRegistry, + StableToStableRate, + >::stable_to_stable( + pool_currency, currency_id, amount + ) + .unwrap(); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrency { + swap: Swap { + currency_in: pool_currency, + currency_out: currency_id, + amount: amount_pool_denominated + } + } + ); + } } /// Sets up required permissions for the investor and executes an From 92bc877e52371561c772494657fe8f90a8e66b7a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 15:18:28 +0200 Subject: [PATCH 82/96] Merge remote-tracking branch 'origin/main' into feat/wf-foreign-investments --- .github/workflows/lints.yml | 8 +- Cargo.lock | 77 +- Cargo.toml | 2 +- libs/mock-builder/src/lib.rs | 21 + libs/mocks/src/lib.rs | 2 + libs/mocks/src/pools.rs | 7 +- libs/mocks/src/try_convert.rs | 41 ++ libs/primitives/Cargo.toml | 11 +- libs/primitives/src/lib.rs | 161 ++++ libs/traits/src/lib.rs | 16 +- libs/types/src/lib.rs | 3 + pallets/ethereum-transaction/src/lib.rs | 185 +---- pallets/ethereum-transaction/src/mock.rs | 4 +- pallets/ethereum-transaction/src/tests.rs | 13 +- pallets/foreign-investments/src/lib.rs | 1 - pallets/investments/src/lib.rs | 3 + pallets/liquidity-pools-gateway/Cargo.toml | 2 +- .../axelar-gateway-precompile/Cargo.toml | 4 + .../axelar-gateway-precompile/src/lib.rs | 39 +- .../axelar-gateway-precompile/src/weights.rs | 42 ++ .../routers/Cargo.toml | 2 + .../routers/src/lib.rs | 63 +- .../routers/src/mock.rs | 22 +- .../routers/src/routers/axelar_evm.rs | 38 +- .../routers/src/routers/axelar_xcm.rs | 10 +- .../routers/src/tests.rs | 185 ++--- pallets/liquidity-pools-gateway/src/lib.rs | 246 ++++++- pallets/liquidity-pools-gateway/src/mock.rs | 26 +- pallets/liquidity-pools-gateway/src/origin.rs | 11 +- pallets/liquidity-pools-gateway/src/tests.rs | 326 +++++++- .../liquidity-pools-gateway/src/weights.rs | 72 +- pallets/liquidity-pools/src/lib.rs | 64 +- pallets/liquidity-pools/src/weights.rs | 62 +- pallets/loans/src/tests/mock.rs | 2 +- pallets/order-book/src/lib.rs | 315 +++++--- pallets/order-book/src/tests.rs | 50 +- pallets/pool-registry/src/lib.rs | 7 - pallets/pool-registry/src/mock.rs | 7 +- pallets/pool-system/src/impls.rs | 8 +- pallets/pool-system/src/lib.rs | 28 +- pallets/pool-system/src/mock.rs | 5 +- pallets/pool-system/src/tests/mod.rs | 14 +- pallets/pool-system/src/tranches.rs | 17 +- pallets/transfer-allowlist/src/lib.rs | 18 +- pallets/transfer-allowlist/src/mock.rs | 2 +- pallets/transfer-allowlist/src/weights.rs | 230 +++++- runtime/altair/Cargo.toml | 2 +- runtime/altair/src/evm.rs | 14 +- runtime/altair/src/lib.rs | 72 +- runtime/altair/src/migrations.rs | 411 +++++------ runtime/altair/src/weights/frame_system.rs | 83 ++- runtime/altair/src/weights/pallet_anchors.rs | 693 ++++++++++++------ runtime/altair/src/weights/pallet_balances.rs | 75 +- .../src/weights/pallet_block_rewards.rs | 50 +- .../src/weights/pallet_collator_allowlist.rs | 28 +- .../src/weights/pallet_collator_selection.rs | 142 ++-- .../altair/src/weights/pallet_collective.rs | 282 ++++--- .../src/weights/pallet_crowdloan_claim.rs | 203 +++-- .../src/weights/pallet_crowdloan_reward.rs | 51 +- .../altair/src/weights/pallet_democracy.rs | 366 ++++++--- runtime/altair/src/weights/pallet_fees.rs | 15 +- runtime/altair/src/weights/pallet_identity.rs | 313 +++++--- .../src/weights/pallet_interest_accrual.rs | 16 +- runtime/altair/src/weights/pallet_keystore.rs | 54 +- runtime/altair/src/weights/pallet_loans.rs | 345 ++++++--- .../src/weights/pallet_migration_manager.rs | 83 ++- runtime/altair/src/weights/pallet_multisig.rs | 121 +-- .../altair/src/weights/pallet_nft_sales.rs | 86 ++- .../altair/src/weights/pallet_permissions.rs | 77 +- .../src/weights/pallet_pool_registry.rs | 155 ++-- .../altair/src/weights/pallet_pool_system.rs | 245 ++++--- runtime/altair/src/weights/pallet_preimage.rs | 155 ++-- runtime/altair/src/weights/pallet_proxy.rs | 178 +++-- .../src/weights/pallet_restricted_tokens.rs | 123 +++- .../altair/src/weights/pallet_scheduler.rs | 150 ++-- runtime/altair/src/weights/pallet_session.rs | 31 +- .../altair/src/weights/pallet_timestamp.rs | 25 +- runtime/altair/src/weights/pallet_treasury.rs | 92 ++- runtime/altair/src/weights/pallet_uniques.rs | 400 ++++++---- runtime/altair/src/weights/pallet_utility.rs | 52 +- runtime/altair/src/weights/pallet_vesting.rs | 191 +++-- runtime/altair/src/xcm.rs | 87 ++- runtime/centrifuge/Cargo.toml | 42 +- runtime/centrifuge/src/evm.rs | 15 +- runtime/centrifuge/src/lib.rs | 253 ++++++- runtime/centrifuge/src/migrations.rs | 220 +----- .../src/weights/cumulus_pallet_xcmp_queue.rs | 23 +- .../centrifuge/src/weights/frame_system.rs | 79 +- runtime/centrifuge/src/weights/mod.rs | 1 + .../centrifuge/src/weights/pallet_anchors.rs | 691 +++++++++++------ .../centrifuge/src/weights/pallet_balances.rs | 73 +- .../src/weights/pallet_block_rewards.rs | 48 +- .../src/weights/pallet_collator_allowlist.rs | 26 +- .../src/weights/pallet_collator_selection.rs | 140 ++-- .../src/weights/pallet_collective.rs | 278 ++++--- .../src/weights/pallet_crowdloan_claim.rs | 201 +++-- .../src/weights/pallet_crowdloan_reward.rs | 49 +- .../src/weights/pallet_democracy.rs | 364 ++++++--- .../src/weights/pallet_elections_phragmen.rs | 271 ++++--- runtime/centrifuge/src/weights/pallet_fees.rs | 13 +- .../centrifuge/src/weights/pallet_identity.rs | 311 +++++--- .../src/weights/pallet_interest_accrual.rs | 14 +- .../centrifuge/src/weights/pallet_keystore.rs | 52 +- .../src/weights/pallet_liquidity_rewards.rs | 37 + .../centrifuge/src/weights/pallet_loans.rs | 341 ++++++--- .../src/weights/pallet_migration_manager.rs | 81 +- .../centrifuge/src/weights/pallet_multisig.rs | 119 +-- .../src/weights/pallet_permissions.rs | 75 +- .../src/weights/pallet_pool_registry.rs | 156 ++-- .../src/weights/pallet_pool_system.rs | 243 ++++-- .../centrifuge/src/weights/pallet_preimage.rs | 153 ++-- .../centrifuge/src/weights/pallet_proxy.rs | 180 +++-- .../src/weights/pallet_restricted_tokens.rs | 121 ++- .../src/weights/pallet_scheduler.rs | 148 ++-- .../centrifuge/src/weights/pallet_session.rs | 29 +- .../src/weights/pallet_timestamp.rs | 21 +- .../centrifuge/src/weights/pallet_treasury.rs | 90 ++- .../centrifuge/src/weights/pallet_uniques.rs | 398 ++++++---- .../centrifuge/src/weights/pallet_utility.rs | 50 +- .../centrifuge/src/weights/pallet_vesting.rs | 171 +++-- runtime/centrifuge/src/xcm.rs | 108 ++- runtime/common/Cargo.toml | 24 +- runtime/common/src/account_conversion.rs | 43 +- runtime/common/src/apis/account_conversion.rs | 25 + runtime/common/src/apis/mod.rs | 2 + runtime/common/src/evm/precompile.rs | 7 +- runtime/common/src/gateway.rs | 37 + runtime/common/src/lib.rs | 262 +++++-- .../src/migrations/asset_registry_xcmv3.rs | 235 ++++++ runtime/common/src/migrations/mod.rs | 1 + runtime/common/src/migrations/nuke.rs | 13 +- runtime/common/src/xcm.rs | 440 +++++++++++ runtime/development/Cargo.toml | 8 +- runtime/development/src/evm.rs | 9 +- runtime/development/src/lib.rs | 148 ++-- runtime/development/src/liquidity_pools.rs | 9 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 56 ++ .../development/src/weights/frame_system.rs | 118 ++- runtime/development/src/weights/mod.rs | 17 + .../development/src/weights/pallet_anchors.rs | 510 +++++++++++++ .../src/weights/pallet_balances.rs | 119 +-- .../src/weights/pallet_block_rewards.rs | 69 +- .../src/weights/pallet_collator_allowlist.rs | 58 +- .../src/weights/pallet_collator_selection.rs | 187 +++-- .../src/weights/pallet_collective.rs | 274 +++++++ .../src/weights/pallet_crowdloan_claim.rs | 204 ++++-- .../src/weights/pallet_crowdloan_reward.rs | 74 +- .../src/weights/pallet_democracy.rs | 376 ++++++++++ .../src/weights/pallet_elections_phragmen.rs | 277 +++++++ .../development/src/weights/pallet_fees.rs | 39 +- .../src/weights/pallet_identity.rs | 320 ++++++++ .../src/weights/pallet_interest_accrual.rs | 44 ++ .../src/weights/pallet_keystore.rs | 89 ++- .../development/src/weights/pallet_loans.rs | 327 +++++++-- .../src/weights/pallet_migration_manager.rs | 132 ++-- .../src/weights/pallet_multisig.rs | 139 ++++ .../src/weights/pallet_order_book.rs | 54 +- .../src/weights/pallet_permissions.rs | 116 ++- .../src/weights/pallet_pool_registry.rs | 184 +++-- .../src/weights/pallet_pool_system.rs | 291 +++++--- .../src/weights/pallet_preimage.rs | 187 +++++ .../development/src/weights/pallet_proxy.rs | 197 +++++ .../src/weights/pallet_restricted_tokens.rs | 169 +++-- .../src/weights/pallet_scheduler.rs | 176 +++++ .../development/src/weights/pallet_session.rs | 45 +- .../src/weights/pallet_timestamp.rs | 54 ++ .../src/weights/pallet_transfer_allowlist.rs | 8 + .../src/weights/pallet_treasury.rs | 118 +++ .../development/src/weights/pallet_uniques.rs | 418 +++++++++++ .../development/src/weights/pallet_utility.rs | 78 ++ .../development/src/weights/pallet_vesting.rs | 190 +++++ runtime/development/src/xcm.rs | 155 ++-- runtime/integration-tests/Cargo.toml | 1 + .../src/ethereum_transaction/pallet.rs | 44 +- .../src/liquidity_pools/gateway.rs | 10 +- .../liquidity_pools/pallet/development/mod.rs | 1 + .../liquidity_pools/add_allow_upgrade.rs | 40 +- .../liquidity_pools/foreign_investments.rs | 150 ++-- .../tests/liquidity_pools/setup.rs | 42 +- .../tests/liquidity_pools/transfers.rs | 12 +- .../pallet/development/tests/mod.rs | 6 +- .../development/tests/routers/axelar_evm.rs | 37 +- .../development/tests/routers/ethereum_xcm.rs | 36 +- .../pallet/development/transfers.rs | 245 +++++++ runtime/integration-tests/src/utils/evm.rs | 4 +- src/chain_spec.rs | 24 +- 186 files changed, 15751 insertions(+), 5656 deletions(-) create mode 100644 libs/mocks/src/try_convert.rs create mode 100644 pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/weights.rs create mode 100644 runtime/centrifuge/src/weights/pallet_liquidity_rewards.rs create mode 100644 runtime/common/src/apis/account_conversion.rs create mode 100644 runtime/common/src/gateway.rs create mode 100644 runtime/common/src/migrations/asset_registry_xcmv3.rs create mode 100644 runtime/common/src/xcm.rs create mode 100644 runtime/development/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 runtime/development/src/weights/pallet_anchors.rs create mode 100644 runtime/development/src/weights/pallet_collective.rs create mode 100644 runtime/development/src/weights/pallet_democracy.rs create mode 100644 runtime/development/src/weights/pallet_elections_phragmen.rs create mode 100644 runtime/development/src/weights/pallet_identity.rs create mode 100644 runtime/development/src/weights/pallet_interest_accrual.rs create mode 100644 runtime/development/src/weights/pallet_multisig.rs create mode 100644 runtime/development/src/weights/pallet_preimage.rs create mode 100644 runtime/development/src/weights/pallet_proxy.rs create mode 100644 runtime/development/src/weights/pallet_scheduler.rs create mode 100644 runtime/development/src/weights/pallet_timestamp.rs create mode 100644 runtime/development/src/weights/pallet_treasury.rs create mode 100644 runtime/development/src/weights/pallet_uniques.rs create mode 100644 runtime/development/src/weights/pallet_utility.rs create mode 100644 runtime/development/src/weights/pallet_vesting.rs create mode 100644 runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index fd1fa29fc3..abc9c8fc43 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - target: [fmt, taplo, clippy] + target: [fmt, clippy] runs-on: ${{ matrix.os }} env: RUST_TOOLCHAIN: "nightly-2022-11-14" @@ -31,12 +31,6 @@ jobs: with: toolchain: ${{ env.RUST_TOOLCHAIN }} default: true - - name: Install taplo - uses: actions-rs/install@v0.1 - with: - crate: taplo-cli - version: 0.7.2 - use-tool-cache: true - uses: Swatinem/rust-cache@cb2cf0cc7c5198d3364b9630e2c3d457f160790c - name: Run lints run: ./ci/script.sh diff --git a/Cargo.lock b/Cargo.lock index 2efb6d4b34..49cc67ef0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,7 +190,7 @@ dependencies = [ [[package]] name = "altair-runtime" -version = "0.10.30" +version = "0.10.32" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", @@ -214,7 +214,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", "liquidity-pools-gateway-routers", "log", "moonbeam-relay-encoder", @@ -605,6 +605,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "axelar-gateway-precompile" version = "0.1.0" dependencies = [ + "cfg-traits", "cfg-types", "ethabi 18.0.0", "fp-evm", @@ -1079,7 +1080,7 @@ dependencies = [ "frame-system", "futures", "getrandom 0.2.10", - "hex-literal 0.2.2", + "hex-literal", "jsonrpsee", "log", "pallet-anchors", @@ -1136,8 +1137,9 @@ dependencies = [ [[package]] name = "centrifuge-runtime" -version = "0.10.19" +version = "0.10.20" dependencies = [ + "axelar-gateway-precompile", "cfg-primitives", "cfg-traits", "cfg-types", @@ -1160,8 +1162,10 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", + "liquidity-pools-gateway-routers", "log", + "moonbeam-relay-encoder", "orml-asset-registry", "orml-oracle", "orml-tokens", @@ -1186,6 +1190,7 @@ dependencies = [ "pallet-democracy", "pallet-elections-phragmen", "pallet-ethereum", + "pallet-ethereum-transaction", "pallet-evm", "pallet-evm-chain-id", "pallet-evm-precompile-dispatch", @@ -1194,6 +1199,9 @@ dependencies = [ "pallet-interest-accrual", "pallet-investments", "pallet-keystore", + "pallet-liquidity-pools", + "pallet-liquidity-pools-gateway", + "pallet-liquidity-rewards", "pallet-loans", "pallet-membership", "pallet-migration-manager", @@ -1217,6 +1225,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", + "pallet-xcm-transactor", "parachain-info", "parity-scale-codec 3.6.4", "polkadot-parachain", @@ -1241,6 +1250,7 @@ dependencies = [ "xcm", "xcm-builder", "xcm-executor", + "xcm-primitives", ] [[package]] @@ -1300,8 +1310,11 @@ dependencies = [ "sp-arithmetic", "sp-consensus-aura", "sp-core", + "sp-io", "sp-runtime", "sp-std", + "xcm", + "xcm-executor", ] [[package]] @@ -1348,7 +1361,7 @@ dependencies = [ "cfg-utils", "frame-support", "hex", - "hex-literal 0.3.4", + "hex-literal", "orml-asset-registry", "parity-scale-codec 3.6.4", "scale-info", @@ -2670,7 +2683,7 @@ dependencies = [ [[package]] name = "development-runtime" -version = "0.10.20" +version = "0.10.21" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", @@ -2697,7 +2710,7 @@ dependencies = [ "frame-try-runtime", "getrandom 0.2.10", "hex", - "hex-literal 0.3.4", + "hex-literal", "liquidity-pools-gateway-routers", "moonbeam-relay-encoder", "orml-asset-registry", @@ -4443,31 +4456,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70693199b3cf4552f3fa720b54163927a3ebed2aef240efaf556033ab336a11" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] - [[package]] name = "hex-literal" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" -[[package]] -name = "hex-literal-impl" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59448fc2f82a5fb6907f78c3d69d843e82ff5b051923313cc4438cb0c7b745a8" -dependencies = [ - "proc-macro-hack", -] - [[package]] name = "hkdf" version = "0.12.3" @@ -5056,7 +5050,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", "kusama-runtime-constants", "log", "pallet-authority-discovery", @@ -5814,6 +5808,7 @@ dependencies = [ "ethabi 16.0.0", "frame-support", "frame-system", + "lazy_static", "orml-traits", "pallet-balances", "pallet-ethereum", @@ -9679,7 +9674,7 @@ version = "0.9.38" source = "git+https://github.com/paritytech//polkadot?rev=097ffd245c42aeff28cf80f8a3568e1bee2e7da7#097ffd245c42aeff28cf80f8a3568e1bee2e7da7" dependencies = [ "bitvec 1.0.1", - "hex-literal 0.3.4", + "hex-literal", "parity-scale-codec 3.6.4", "polkadot-core-primitives", "polkadot-parachain", @@ -9745,7 +9740,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", @@ -9949,7 +9944,7 @@ dependencies = [ "frame-support", "frame-system-rpc-runtime-api", "futures", - "hex-literal 0.3.4", + "hex-literal", "kusama-runtime", "kvdb", "kvdb-rocksdb", @@ -10288,12 +10283,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.66" @@ -10848,7 +10837,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", @@ -11001,6 +10990,7 @@ name = "runtime-common" version = "1.0.0" dependencies = [ "axelar-gateway-precompile", + "cfg-mocks", "cfg-primitives", "cfg-traits", "cfg-types", @@ -11008,14 +10998,16 @@ dependencies = [ "fp-self-contained", "frame-support", "frame-system", - "hex-literal 0.2.2", + "hex-literal", "log", + "orml-asset-registry", "orml-oracle", "orml-traits", "pallet-anchors", "pallet-authorship", "pallet-balances", "pallet-base-fee", + "pallet-collective", "pallet-data-collector", "pallet-ethereum", "pallet-evm", @@ -11028,10 +11020,13 @@ dependencies = [ "pallet-evm-precompile-simple", "pallet-investments", "pallet-liquidity-pools", + "pallet-liquidity-pools-gateway", "pallet-loans", "pallet-pool-system", "pallet-treasury", + "parachain-info", "parity-scale-codec 3.6.4", + "polkadot-parachain", "scale-info", "serde", "smallvec", @@ -11042,6 +11037,7 @@ dependencies = [ "sp-runtime", "sp-std", "xcm", + "xcm-executor", "xcm-primitives", ] @@ -11078,6 +11074,7 @@ dependencies = [ "pallet-collator-selection", "pallet-collective", "pallet-democracy", + "pallet-ethereum", "pallet-ethereum-transaction", "pallet-evm", "pallet-evm-chain-id", @@ -15433,7 +15430,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.3.4", + "hex-literal", "log", "pallet-authority-discovery", "pallet-authorship", diff --git a/Cargo.toml b/Cargo.toml index 7836d5042b..1d03ea1f74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ async-trait = "0.1" clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0", default-features = false } futures = "0.3.25" -hex-literal = "0.2.1" +hex-literal = "0.3.4" jsonrpsee = { version = "0.16.2", features = ["server", "macros"] } log = "0.4.8" serde = { version = "1.0.119", features = ["derive"] } diff --git a/libs/mock-builder/src/lib.rs b/libs/mock-builder/src/lib.rs index 4aa1ef8b26..9a24d707cc 100644 --- a/libs/mock-builder/src/lib.rs +++ b/libs/mock-builder/src/lib.rs @@ -329,6 +329,15 @@ macro_rules! register_call { }}; } +/// Register a mock function into the mock function storage for a pallet with +/// instances. Same as `register()` but it uses as locator who calls this macro. +#[macro_export] +macro_rules! register_call_instance { + ($f:expr) => {{ + $crate::register::, _, _, _, _>(|| (), $f) + }}; +} + /// Execute a function from the function storage. /// Same as `execute()` but it uses as locator who calls this macro. #[macro_export] @@ -336,4 +345,16 @@ macro_rules! execute_call { ($input:expr) => {{ $crate::execute::, _, _, _>(|| (), $input) }}; + ($input:expr, $gen:expr) => {{ + $crate::execute::, _, _, _>(|| (), $input) + }}; +} + +/// Execute a function from the function storage for a pallet with instances. +/// Same as `execute()` but it uses as locator who calls this macro. +#[macro_export] +macro_rules! execute_call_instance { + ($input:expr) => {{ + $crate::execute::, _, _, _>(|| (), $input) + }}; } diff --git a/libs/mocks/src/lib.rs b/libs/mocks/src/lib.rs index acacb4ce25..1fc48e7e8a 100644 --- a/libs/mocks/src/lib.rs +++ b/libs/mocks/src/lib.rs @@ -7,6 +7,7 @@ mod permissions; mod pools; mod rewards; mod time; +mod try_convert; mod write_off_policy; pub use change_guard::pallet_mock_change_guard; @@ -18,6 +19,7 @@ pub use permissions::pallet as pallet_mock_permissions; pub use pools::pallet as pallet_mock_pools; pub use rewards::pallet as pallet_mock_rewards; pub use time::pallet as pallet_mock_time; +pub use try_convert::pallet as pallet_mock_try_convert; pub use write_off_policy::pallet as pallet_mock_write_off_policy; #[cfg(test)] diff --git a/libs/mocks/src/pools.rs b/libs/mocks/src/pools.rs index 53b59fdddd..48c7b13580 100644 --- a/libs/mocks/src/pools.rs +++ b/libs/mocks/src/pools.rs @@ -21,7 +21,7 @@ pub mod pallet { + MaxEncodedLen; type TrancheId: Parameter + Member + Debug + Copy + Default + TypeInfo + MaxEncodedLen; type Balance; - type Rate; + type BalanceRatio; type CurrencyId; } @@ -78,7 +78,6 @@ pub mod pallet { impl PoolInspect for Pallet { type Moment = Moment; type PoolId = T::PoolId; - type Rate = T::Rate; type TrancheId = T::TrancheId; fn pool_exists(a: T::PoolId) -> bool { @@ -99,15 +98,15 @@ pub mod pallet { } impl TrancheTokenPrice for Pallet { + type BalanceRatio = T::BalanceRatio; type Moment = Moment; type PoolId = T::PoolId; - type Rate = T::Rate; type TrancheId = T::TrancheId; fn get( a: T::PoolId, b: T::TrancheId, - ) -> Option> { + ) -> Option> { execute_call!((a, b)) } } diff --git a/libs/mocks/src/try_convert.rs b/libs/mocks/src/try_convert.rs new file mode 100644 index 0000000000..bce85c40a0 --- /dev/null +++ b/libs/mocks/src/try_convert.rs @@ -0,0 +1,41 @@ +#[frame_support::pallet] +pub mod pallet { + use cfg_traits::TryConvert; + use frame_support::pallet_prelude::*; + use mock_builder::{execute_call_instance, register_call_instance}; + + #[pallet::config] + pub trait Config: frame_system::Config { + type From; + + type To; + + type Error; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::storage] + pub(super) type CallIds, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + ::Output, + mock_builder::CallId, + >; + + impl, I: 'static> Pallet { + pub fn mock_try_convert(f: impl Fn(T::From) -> Result + 'static) { + register_call_instance!(f); + } + } + + impl, I: 'static> TryConvert for Pallet { + type Error = T::Error; + + fn try_convert(from: T::From) -> Result { + execute_call_instance!(from) + } + } +} diff --git a/libs/primitives/Cargo.toml b/libs/primitives/Cargo.toml index 813edac75f..a7b9805a11 100644 --- a/libs/primitives/Cargo.toml +++ b/libs/primitives/Cargo.toml @@ -19,6 +19,7 @@ serde = { version = "1.0.119" } sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -27,9 +28,13 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-collective = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } -# cumuluse primitives dependencies +# cumulus primitives dependencies cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.38" } +# XCM primitives dependencies +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } + [features] default = ["std"] runtime-benchmarks = [ @@ -37,10 +42,12 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] std = [ "serde/std", "codec/std", + "sp-io/std", "sp-std/std", "scale-info/std", "sp-core/std", @@ -51,6 +58,8 @@ std = [ "pallet-collective/std", "sp-consensus-aura/std", "cumulus-primitives-core/std", + "xcm/std", + "xcm-executor/std", ] try-runtime = [ "frame-support/try-runtime", diff --git a/libs/primitives/src/lib.rs b/libs/primitives/src/lib.rs index b8c0d3f28e..2f17fc6811 100644 --- a/libs/primitives/src/lib.rs +++ b/libs/primitives/src/lib.rs @@ -269,6 +269,9 @@ pub mod constants { /// Transaction pallet. As per: /// pub const TRANSACTION_RECOVERY_ID: u64 = 42; + + /// The safe XCM version of pallet-xcm, same as on relay chain + pub const SAFE_XCM_VERSION: u32 = xcm::opaque::v2::VERSION; } /// Listing of parachains we integrate with. @@ -336,3 +339,161 @@ pub mod liquidity_pools { } } } + +pub mod xcm { + use codec::{Compact, Encode}; + use sp_io::hashing::blake2_256; + use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; + use xcm::prelude::{ + AccountId32, AccountKey20, Here, MultiLocation, PalletInstance, Parachain, X1, + }; + use xcm_executor::traits::Convert; + + /// NOTE: Copied from + /// + /// temporary struct that mimics the behavior of the upstream type that we + /// will move to once we update this repository to Polkadot 0.9.43+. + pub struct HashedDescriptionDescribeFamilyAllTerminal(PhantomData); + impl + Clone> HashedDescriptionDescribeFamilyAllTerminal { + fn describe_location_suffix(l: &MultiLocation) -> Result, ()> { + match (l.parents, &l.interior) { + (0, Here) => Ok(Vec::new()), + (0, X1(PalletInstance(i))) => { + Ok((b"Pallet", Compact::::from(*i as u32)).encode()) + } + (0, X1(AccountId32 { id, .. })) => Ok((b"AccountId32", id).encode()), + (0, X1(AccountKey20 { key, .. })) => Ok((b"AccountKey20", key).encode()), + _ => Err(()), + } + } + } + + impl + Clone> Convert + for HashedDescriptionDescribeFamilyAllTerminal + { + fn convert_ref(location: impl Borrow) -> Result { + let l = location.borrow(); + let to_hash = match (l.parents, l.interior.first()) { + (0, Some(Parachain(index))) => { + let tail = l.interior.split_first().0; + let interior = Self::describe_location_suffix(&tail.into())?; + (b"ChildChain", Compact::::from(*index), interior).encode() + } + (1, Some(Parachain(index))) => { + let tail = l.interior.split_first().0; + let interior = Self::describe_location_suffix(&tail.into())?; + (b"SiblingChain", Compact::::from(*index), interior).encode() + } + (1, _) => { + let tail = l.interior.into(); + let interior = Self::describe_location_suffix(&tail)?; + (b"ParentChain", interior).encode() + } + _ => return Err(()), + }; + Ok(blake2_256(&to_hash).into()) + } + + fn reverse_ref(_: impl Borrow) -> Result { + Err(()) + } + } + + #[test] + fn test_hashed_family_all_terminal_converter() { + use xcm::prelude::X2; + + type Converter = HashedDescriptionDescribeFamilyAllTerminal; + + assert_eq!( + [ + 129, 211, 14, 6, 146, 54, 225, 200, 135, 103, 248, 244, 125, 112, 53, 133, 91, 42, + 215, 236, 154, 199, 191, 208, 110, 148, 223, 55, 92, 216, 250, 34 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 0, + interior: X2( + Parachain(1), + AccountId32 { + network: None, + id: [0u8; 32] + } + ), + }) + .unwrap() + ); + assert_eq!( + [ + 17, 142, 105, 253, 199, 34, 43, 136, 155, 48, 12, 137, 155, 219, 155, 110, 93, 181, + 93, 252, 124, 60, 250, 195, 229, 86, 31, 220, 121, 111, 254, 252 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 1, + interior: X2( + Parachain(1), + AccountId32 { + network: None, + id: [0u8; 32] + } + ), + }) + .unwrap() + ); + assert_eq!( + [ + 237, 65, 190, 49, 53, 182, 196, 183, 151, 24, 214, 23, 72, 244, 235, 87, 187, 67, + 52, 122, 195, 192, 10, 58, 253, 49, 0, 112, 175, 224, 125, 66 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 0, + interior: X2( + Parachain(1), + AccountKey20 { + network: None, + key: [0u8; 20] + } + ), + }) + .unwrap() + ); + assert_eq!( + [ + 226, 225, 225, 162, 254, 156, 113, 95, 68, 155, 160, 118, 126, 18, 166, 132, 144, + 19, 8, 204, 228, 112, 164, 189, 179, 124, 249, 1, 168, 110, 151, 50 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 1, + interior: X2( + Parachain(1), + AccountKey20 { + network: None, + key: [0u8; 20] + } + ), + }) + .unwrap() + ); + assert_eq!( + [ + 254, 186, 179, 229, 13, 24, 84, 36, 84, 35, 64, 95, 114, 136, 62, 69, 247, 74, 215, + 104, 121, 114, 53, 6, 124, 46, 42, 245, 121, 197, 12, 208 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 1, + interior: X2(Parachain(2), PalletInstance(3)), + }) + .unwrap() + ); + assert_eq!( + [ + 217, 56, 0, 36, 228, 154, 250, 26, 200, 156, 1, 39, 254, 162, 16, 187, 107, 67, 27, + 16, 218, 254, 250, 184, 6, 27, 216, 138, 194, 93, 23, 165 + ], + Converter::<[u8; 32]>::convert(MultiLocation { + parents: 1, + interior: Here, + }) + .unwrap() + ); + } +} diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 35d6b48777..bc8ced19e8 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -126,7 +126,6 @@ pub trait PoolNAV { pub trait PoolInspect { type PoolId; type TrancheId; - type Rate; type Moment; /// check if the pool exists @@ -144,13 +143,13 @@ pub trait PoolInspect { pub trait TrancheTokenPrice { type PoolId; type TrancheId; - type Rate; + type BalanceRatio; type Moment; fn get( pool_id: Self::PoolId, tranche_id: Self::TrancheId, - ) -> Option>; + ) -> Option>; } /// Variants for valid Pool updates to send out as events @@ -165,7 +164,6 @@ pub enum UpdateState { pub trait PoolMutate { type Balance; type CurrencyId; - type Rate; type MaxTokenNameLength: Get; type MaxTokenSymbolLength: Get; type MaxTranches: Get; @@ -604,3 +602,13 @@ pub trait SimpleCurrencyConversion { amount_out: Self::Balance, ) -> Result; } + +/// A trait for trying to convert between two types. +// TODO: Remove usage for the one from Polkadot once we are on the same version +pub trait TryConvert { + type Error; + + /// Attempt to make conversion. If returning [Result::Err], the inner must + /// always be `a`. + fn try_convert(a: A) -> Result; +} diff --git a/libs/types/src/lib.rs b/libs/types/src/lib.rs index 019b70e070..a72e013551 100644 --- a/libs/types/src/lib.rs +++ b/libs/types/src/lib.rs @@ -35,3 +35,6 @@ pub mod xcm; /// The EVM Chain ID /// The type should accomodate all chain ids listed on . pub type EVMChainId = u64; + +/// A raw para ID +pub type ParaId = u32; diff --git a/pallets/ethereum-transaction/src/lib.rs b/pallets/ethereum-transaction/src/lib.rs index bb0680dde5..55132e4ae5 100644 --- a/pallets/ethereum-transaction/src/lib.rs +++ b/pallets/ethereum-transaction/src/lib.rs @@ -14,15 +14,12 @@ use cfg_primitives::TRANSACTION_RECOVERY_ID; use cfg_traits::ethereum::EthereumTransactor; use ethereum::{LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2}; -use fp_evm::CallOrCreateInfo; use frame_support::{ dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, pallet_prelude::*, }; pub use pallet::*; -use pallet_evm::{ExitError, ExitFatal, ExitReason}; use sp_core::{H160, H256, U256}; -use sp_std::vec::Vec; #[cfg(test)] mod mock; @@ -32,6 +29,8 @@ mod tests; #[frame_support::pallet] pub mod pallet { + use frame_system::pallet_prelude::OriginFor; + use super::*; #[pallet::pallet] @@ -39,99 +38,37 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_ethereum::Config { - /// The event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; + pub trait Config: frame_system::Config + pallet_ethereum::Config + where + OriginFor: + From + Into>>, + { } /// Storage for nonce. #[pallet::storage] + #[pallet::getter(fn nonce)] pub(crate) type Nonce = StorageValue<_, U256, ValueQuery>; - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - /// A call was executed. - Executed { - from: H160, - to: H160, - exit_reason: ExitReason, - value: Vec, - }, - } - - #[pallet::error] - pub enum Error { - /// Trying to pop from an empty stack. - StackUnderflow, - - /// Trying to push into a stack over stack limit. - StackOverflow, - - /// Jump destination is invalid. - InvalidJump, - - /// An opcode accesses memory region, but the region is invalid. - InvalidRange, - - /// Encountered the designated invalid opcode. - DesignatedInvalid, - - /// Call stack is too deep (runtime). - CallTooDeep, - - /// Create opcode encountered collision (runtime). - CreateCollision, - - /// Create init code exceeds limit (runtime). - CreateContractLimit, - - /// Invalid opcode during execution or starting byte is 0xef. See [EIP-3541](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3541.md). - InvalidCode(u8), - - /// An opcode accesses external information, but the request is off - /// offset limit (runtime). - OutOfOffset, - - /// Execution runs out of gas (runtime). - OutOfGas, - - /// Not enough fund to start the execution (runtime). - OutOfFund, - - /// PC underflowed (unused). - PCUnderflow, - - /// Attempt to create an empty account (runtime, unused). - CreateEmpty, - - /// The operation is not supported. - NotSupported, - /// The trap (interrupt) is unhandled. - UnhandledInterrupt, - - /// Machine encountered an explicit revert. - Reverted, - - /// Unexpected result when executing a transaction. - UnexpectedExecuteResult, - - /// Other normal errors. - Other, - } - - impl Pallet { - fn get_transaction_signature() -> Option { - //TODO(cdamian): Same signature as the one in ethereum-xcm. + impl Pallet + where + OriginFor: + From + Into>>, + { + pub fn get_transaction_signature() -> Option { TransactionSignature::new( TRANSACTION_RECOVERY_ID, - H256::from_low_u64_be(1u64), - H256::from_low_u64_be(1u64), + H256::from_low_u64_be(2u64), + H256::from_low_u64_be(2u64), ) } } - impl EthereumTransactor for Pallet { + impl EthereumTransactor for Pallet + where + OriginFor: + From + Into>>, + { /// This implementation serves as a wrapper around the Ethereum pallet /// execute functionality. It keeps track of the nonce used for each /// call and builds a fake signature for executing the provided call. @@ -170,10 +107,9 @@ pub mod pallet { Nonce::::put(nonce.saturating_add(U256::one())); - let (_target, _value, info) = pallet_ethereum::Pallet::::execute( - from, - &transaction, - Some(T::config().clone()), + pallet_ethereum::Pallet::::transact( + pallet_ethereum::Origin::EthereumTransaction(from).into(), + transaction, ) .map_err(|e| { let weight = e.post_info.actual_weight.map_or(Weight::zero(), |w| w); @@ -185,72 +121,15 @@ pub mod pallet { }, error: e.error, } - })?; - - let dispatch_info = PostDispatchInfo { - actual_weight: Some(read_weight), + }) + .map(|dispatch_info| PostDispatchInfo { pays_fee: Pays::Yes, - }; - - match info { - CallOrCreateInfo::Call(call_info) => { - Self::deposit_event(Event::Executed { - from, - to, - exit_reason: call_info.exit_reason.clone(), - value: call_info.value.clone(), - }); - - match call_info.exit_reason { - ExitReason::Succeed(_) => Ok(dispatch_info), - ExitReason::Error(e) => Err(DispatchErrorWithPostInfo { - post_info: dispatch_info, - error: map_evm_error::(e).into(), - }), - ExitReason::Revert(_) => Err(DispatchErrorWithPostInfo { - post_info: dispatch_info, - error: Error::::Reverted.into(), - }), - ExitReason::Fatal(e) => Err(DispatchErrorWithPostInfo { - post_info: dispatch_info, - error: map_evm_fatal_error::(e).into(), - }), - } - } - CallOrCreateInfo::Create(_) => Err(DispatchErrorWithPostInfo { - post_info: dispatch_info, - error: Error::::UnexpectedExecuteResult.into(), - }), - } - } - } - - fn map_evm_error(e: ExitError) -> Error { - match e { - ExitError::StackUnderflow => Error::StackUnderflow, - ExitError::StackOverflow => Error::StackOverflow, - ExitError::InvalidJump => Error::InvalidJump, - ExitError::InvalidRange => Error::InvalidRange, - ExitError::DesignatedInvalid => Error::DesignatedInvalid, - ExitError::CallTooDeep => Error::CallTooDeep, - ExitError::CreateCollision => Error::CreateCollision, - ExitError::CreateContractLimit => Error::CreateContractLimit, - ExitError::InvalidCode(opcode) => Error::InvalidCode(opcode.0), - ExitError::OutOfOffset => Error::OutOfOffset, - ExitError::OutOfGas => Error::OutOfGas, - ExitError::OutOfFund => Error::OutOfFund, - ExitError::PCUnderflow => Error::PCUnderflow, - ExitError::CreateEmpty => Error::CreateEmpty, - ExitError::Other(_) => Error::Other, - } - } - - fn map_evm_fatal_error(e: ExitFatal) -> Error { - match e { - ExitFatal::NotSupported => Error::NotSupported, - ExitFatal::UnhandledInterrupt => Error::UnhandledInterrupt, - ExitFatal::CallErrorAsFatal(e) => map_evm_error(e), - ExitFatal::Other(_) => Error::Other, + actual_weight: dispatch_info + .actual_weight + .map_or(Some(read_weight), |weight| { + Some(weight.saturating_add(read_weight)) + }), + }) } } } diff --git a/pallets/ethereum-transaction/src/mock.rs b/pallets/ethereum-transaction/src/mock.rs index 5e9fc26cf6..3f4c85bae0 100644 --- a/pallets/ethereum-transaction/src/mock.rs +++ b/pallets/ethereum-transaction/src/mock.rs @@ -183,9 +183,7 @@ impl pallet_ethereum::Config for Runtime { type StateRoot = IntermediateStateRoot; } -impl pallet_ethereum_transaction::Config for Runtime { - type RuntimeEvent = RuntimeEvent; -} +impl pallet_ethereum_transaction::Config for Runtime {} pub fn new_test_ext() -> sp_io::TestExternalities { let storage = frame_system::GenesisConfig::default() diff --git a/pallets/ethereum-transaction/src/tests.rs b/pallets/ethereum-transaction/src/tests.rs index cdfe6b860e..e7752611f3 100644 --- a/pallets/ethereum-transaction/src/tests.rs +++ b/pallets/ethereum-transaction/src/tests.rs @@ -4,7 +4,7 @@ use pallet_evm::{AddressMapping, Error::BalanceLow}; use sp_core::{crypto::AccountId32, H160, U256}; use super::mock::*; -use crate::{pallet::Nonce, Error}; +use crate::pallet::Nonce; mod utils { use super::*; @@ -101,15 +101,20 @@ mod call { assert_eq!(Nonce::::get(), U256::from(0)); - let res = ::call( + // NOTE: We can not check for errors as the internal `pallet-ethereum` logic + // does not transform an EVM error into an Substrate error and return + // `Ok(..)` in theses cases. + // + // We can also not mimic the `pallet-ethereum::Pallet::::transact(..)` + // code path as some needed parts are private. + assert_ok!(::call( sender, to, data.as_slice(), value, gas_price, gas_limit, - ); - assert_eq!(res.err().unwrap().error, Error::::OutOfGas.into()); + )); assert_eq!(Nonce::::get(), U256::from(1)); }); diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index b6793428e4..6855289d3c 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -227,7 +227,6 @@ pub mod pallet { type PoolInspect: PoolInspect< Self::AccountId, Self::CurrencyId, - Rate = Self::Rate, PoolId = Self::PoolId, TrancheId = Self::TrancheId, >; diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index e412bfe8f2..ca4ef743c9 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -199,8 +199,11 @@ pub mod pallet { type WeightInfo: weights::WeightInfo; } + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::hooks] diff --git a/pallets/liquidity-pools-gateway/Cargo.toml b/pallets/liquidity-pools-gateway/Cargo.toml index 5b502a2c22..62f60beff1 100644 --- a/pallets/liquidity-pools-gateway/Cargo.toml +++ b/pallets/liquidity-pools-gateway/Cargo.toml @@ -29,10 +29,10 @@ cfg-traits = { path = "../../libs/traits", default-features = false } cfg-types = { path = "../../libs/types", default-features = false } [dev-dependencies] +cfg-mocks = { path = "../../libs/mocks", features = ["runtime-benchmarks", "std"] } sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } -cfg-mocks = { path = "../../libs/mocks" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } rand = "0.8.5" diff --git a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml index eaa08e0a21..63a59815c0 100644 --- a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml +++ b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml @@ -22,6 +22,7 @@ fp-evm = { git = "https://github.com/PureStake/frontier", default-features = fal pallet-evm = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } precompile-utils = { git = "https://github.com/PureStake/moonbeam", default-features = false, rev = "00b3e3d97806e889b02e1bcb4b69e65433dd805d" } +cfg-traits = { path = "../../../libs/traits", default-features = false } cfg-types = { path = "../../../libs/types", default-features = false } pallet-liquidity-pools-gateway = { path = "../../liquidity-pools-gateway", default-features = false } @@ -41,12 +42,14 @@ std = [ "pallet-evm/std", "pallet-liquidity-pools-gateway/std", "cfg-types/std", + "cfg-traits/std", "ethabi/std", "frame-benchmarking/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "cfg-types/runtime-benchmarks", + "cfg-traits/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -58,6 +61,7 @@ try-runtime = [ "frame-system/try-runtime", "pallet-liquidity-pools-gateway/try-runtime", "cfg-types/try-runtime", + "cfg-traits/try-runtime", "pallet-evm/try-runtime", "sp-runtime/try-runtime", ] diff --git a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs index 1a55104bac..2a272a754b 100644 --- a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs +++ b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs @@ -15,12 +15,15 @@ use cfg_types::domain_address::{Domain, DomainAddress}; use codec::alloc::string::ToString; use ethabi::Token; use fp_evm::PrecompileHandle; +use frame_support::{Blake2_256, StorageHasher}; use pallet_evm::{ExitError, PrecompileFailure}; use precompile_utils::prelude::*; use sp_core::{bounded::BoundedVec, ConstU32, H160, H256, U256}; -use sp_runtime::DispatchResult; +use sp_runtime::{DispatchError, DispatchResult}; use sp_std::vec::Vec; +pub use crate::weights::WeightInfo; + pub const MAX_SOURCE_CHAIN_BYTES: u32 = 128; pub const MAX_SOURCE_ADDRESS_BYTES: u32 = 32; pub const MAX_TOKEN_SYMBOL_BYTES: u32 = 32; @@ -32,6 +35,8 @@ pub type Bytes = BoundedBytes>; pub use pallet::*; +pub mod weights; + #[derive( PartialEq, Clone, @@ -89,6 +94,7 @@ pub mod pallet { use sp_core::{H160, H256}; use super::SourceConverter; + use crate::weights::WeightInfo; // Simple declaration of the `Pallet` type. It is placeholder we use to // implement traits and method. @@ -105,6 +111,8 @@ pub mod pallet { /// The origin that is allowed to set the gateway address we accept /// messageas from type AdminOrigin: EnsureOrigin<::RuntimeOrigin>; + + type WeightInfo: WeightInfo; } #[pallet::storage] @@ -161,7 +169,7 @@ pub mod pallet { #[pallet::call] impl Pallet { - #[pallet::weight(0)] + #[pallet::weight(::WeightInfo::set_gateway())] #[pallet::call_index(0)] pub fn set_gateway(origin: OriginFor, address: H160) -> DispatchResult { ::AdminOrigin::ensure_origin(origin)?; @@ -173,7 +181,7 @@ pub mod pallet { Ok(()) } - #[pallet::weight(0)] + #[pallet::weight(::WeightInfo::set_converter())] #[pallet::call_index(1)] pub fn set_converter( origin: OriginFor, @@ -191,6 +199,22 @@ pub mod pallet { } } +impl cfg_traits::TryConvert<(Vec, Vec), DomainAddress> for Pallet { + type Error = DispatchError; + + fn try_convert(origin: (Vec, Vec)) -> Result { + let (source_chain, source_address) = origin; + + let domain_converter = + SourceConversion::::get(H256::from(Blake2_256::hash(&source_chain))) + .ok_or(Error::::NoConverterForSource)?; + + domain_converter + .try_convert(&source_address) + .ok_or(Error::::AccountBytesMismatchForDomain.into()) + } +} + #[precompile_utils::precompile] impl Pallet where @@ -256,17 +280,16 @@ where })?; Self::execute_call(key, || { - let domain_converter = SourceConversion::::get(H256::from( - sp_io::hashing::blake2_256(source_chain.as_bytes()), - )) - .ok_or(Error::::NoConverterForSource)?; + let domain_converter = + SourceConversion::::get(H256::from(Blake2_256::hash(source_chain.as_bytes()))) + .ok_or(Error::::NoConverterForSource)?; let domain_address = domain_converter .try_convert(source_address.as_bytes()) .ok_or(Error::::AccountBytesMismatchForDomain)?; pallet_liquidity_pools_gateway::Pallet::::process_msg( - pallet_liquidity_pools_gateway::GatewayOrigin::Local(domain_address).into(), + pallet_liquidity_pools_gateway::GatewayOrigin::Domain(domain_address).into(), msg, ) }) diff --git a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/weights.rs b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/weights.rs new file mode 100644 index 0000000000..bfe9fba211 --- /dev/null +++ b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/weights.rs @@ -0,0 +1,42 @@ +// Copyright 2023 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 frame_support::weights::{constants::RocksDbWeight, Weight}; + +pub trait WeightInfo { + fn set_gateway() -> Weight; + fn set_converter() -> Weight; +} + +impl WeightInfo for () { + fn set_gateway() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + fn set_converter() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } +} diff --git a/pallets/liquidity-pools-gateway/routers/Cargo.toml b/pallets/liquidity-pools-gateway/routers/Cargo.toml index 63c4c7aa67..d0ba8b5395 100644 --- a/pallets/liquidity-pools-gateway/routers/Cargo.toml +++ b/pallets/liquidity-pools-gateway/routers/Cargo.toml @@ -40,6 +40,8 @@ pallet-ethereum-transaction = { path = "../../ethereum-transaction", default-fea pallet-liquidity-pools-gateway = { path = "../.", default-features = false } [dev-dependencies] +lazy_static = "1.4.0" + cumulus-primitives-core = { git = "https://github.com/purestake/cumulus", branch = "moonbeam-polkadot-v0.9.38", default-features = false } xcm-builder = { git = "https://github.com/purestake/polkadot", branch = "moonbeam-polkadot-v0.9.38", default-features = false } diff --git a/pallets/liquidity-pools-gateway/routers/src/lib.rs b/pallets/liquidity-pools-gateway/routers/src/lib.rs index ea45ab17fd..e8a5a20445 100644 --- a/pallets/liquidity-pools-gateway/routers/src/lib.rs +++ b/pallets/liquidity-pools-gateway/routers/src/lib.rs @@ -24,6 +24,9 @@ pub const DEFAULT_PROOF_SIZE: u64 = 256 * 1024; // See moonbeam docs: https://docs.moonbeam.network/builders/interoperability/xcm/fees/#:~:text=As%20previously%20mentioned%2C%20Polkadot%20currently,1%2C000%2C000%2C000%20weight%20units%20per%20instruction pub const XCM_INSTRUCTION_WEIGHT: u64 = 1_000_000_000; +/// Multiplier for converting a unit of gas into a unit of Substrate weight +pub const GAS_TO_WEIGHT_MULTIPLIER: u64 = 25_000; + use cfg_traits::{ethereum::EthereumTransactor, liquidity_pools::Router}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ @@ -31,6 +34,7 @@ use frame_support::{ ensure, traits::OriginTrait, }; +use frame_system::pallet_prelude::OriginFor; use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; use scale_info::TypeInfo; use sp_core::{bounded::BoundedVec, ConstU32, H160, H256, U256}; @@ -57,6 +61,12 @@ type CurrencyIdOf = ::CurrencyId; type MessageOf = ::Message; type AccountIdOf = ::AccountId; +/// Maximum size allowed for a byte representation of an Axelar EVM chain +/// string, as found below: +/// +/// +pub const MAX_AXELAR_EVM_CHAIN_SIZE: u32 = 16; + const FUNCTION_NAME: &str = "handle"; const MESSAGE_PARAM: &str = "message"; @@ -75,6 +85,8 @@ where + pallet_ethereum_transaction::Config + pallet_evm::Config, T::AccountId: AsRef<[u8; 32]>, + OriginFor: + From + Into>>, { EthereumXCM(EthereumXCMRouter), AxelarEVM(AxelarEVMRouter), @@ -89,6 +101,8 @@ where + pallet_ethereum_transaction::Config + pallet_evm::Config, T::AccountId: AsRef<[u8; 32]>, + OriginFor: + From + Into>>, { type Message = MessageOf; type Sender = AccountIdOf; @@ -115,6 +129,8 @@ where pub struct EVMRouter where T: frame_system::Config + pallet_ethereum_transaction::Config + pallet_evm::Config, + OriginFor: + From + Into>>, { pub evm_domain: EVMDomain, pub _marker: PhantomData, @@ -124,6 +140,8 @@ impl EVMRouter where T: frame_system::Config + pallet_ethereum_transaction::Config + pallet_evm::Config, T::AccountId: AsRef<[u8; 32]>, + OriginFor: + From + Into>>, { /// Performs an extra check to ensure that the actual contract is deployed /// at the provided address and that the contract code hash matches. @@ -219,27 +237,6 @@ where let ethereum_xcm_call = get_encoded_ethereum_xcm_call::(self.xcm_domain.clone(), msg) .map_err(|_| DispatchError::Other("encoded ethereum xcm call retrieval"))?; - // Note: We are using moonbeams calculation for the ref time here and their - // estimate for the PoV. - // - // - Transact weight: gasLimit * 25000 as moonbeam is doing (Proof size - // limited fixed) - let transact_required_weight_at_most = - Weight::from_ref_time(self.xcm_domain.max_gas_limit * 25_000) - .set_proof_size(DEFAULT_PROOF_SIZE.saturating_div(2)); - - // NOTE: We are choosing an overall weight here to have full control over - // the actual weight usage. - // - // - Transact weight: gasLimit * 25000 as moonbeam is doing (Proof size - // limited fixed) - // - Weight for XCM instructions: Fixed weight * 3 (as we have 3 - // instructions) - let overall_weight = Weight::from_ref_time( - transact_required_weight_at_most.ref_time() + XCM_INSTRUCTION_WEIGHT * 3, - ) - .set_proof_size(DEFAULT_PROOF_SIZE); - pallet_xcm_transactor::Pallet::::transact_through_sovereign( ::RuntimeOrigin::root(), // The destination to which the message should be sent. @@ -249,16 +246,14 @@ where // The currency in which we want to pay fees. CurrencyPayment { currency: Currency::AsCurrencyId(self.xcm_domain.fee_currency.clone()), - fee_amount: Some( - self.xcm_domain.fee_per_second * Into::::into(overall_weight.ref_time()), - ), + fee_amount: Some(self.xcm_domain.fee_amount), }, // The call to be executed in the destination chain. ethereum_xcm_call, OriginKind::SovereignAccount, TransactWeights { - transact_required_weight_at_most, - overall_weight: Some(overall_weight), + transact_required_weight_at_most: self.xcm_domain.transact_required_weight_at_most, + overall_weight: Some(self.xcm_domain.overall_weight), }, )?; @@ -315,16 +310,22 @@ pub struct XcmDomain { /// The target contract address on a given domain. pub contract_address: H160, - /// The max gas_limit we want to propose for a remote evm execution + /// The max gas limit for the execution of the EVM call pub max_gas_limit: u64, + /// The max weight we want to pay for the execution of the Transact call in + /// the destination chain + pub transact_required_weight_at_most: Weight, + + /// The overall max weight we want to pay for the whole XCM message (i.e, + /// all the instructions) + pub overall_weight: Weight, + /// The currency in which execution fees will be paid on pub fee_currency: CurrencyId, - /// The fee per second that will be multiplied with - /// the overall weight of the call to define the fees on the - /// chain that will execute the call. - pub fee_per_second: u128, + /// The fee we use to buy execution for the execution of the Transact call + pub fee_amount: u128, } #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] diff --git a/pallets/liquidity-pools-gateway/routers/src/mock.rs b/pallets/liquidity-pools-gateway/routers/src/mock.rs index 930bc4405c..d94caa1c53 100644 --- a/pallets/liquidity-pools-gateway/routers/src/mock.rs +++ b/pallets/liquidity-pools-gateway/routers/src/mock.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_routers, MessageMock, RouterMock}; +use cfg_traits::TryConvert; use cfg_types::domain_address::DomainAddress; use codec::{Decode, Encode}; use cumulus_primitives_core::{ @@ -23,7 +24,7 @@ use sp_core::{crypto::AccountId32, ByteArray, ConstU16, ConstU32, ConstU64, H160 use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - ConsensusEngineId, + ConsensusEngineId, DispatchError, }; use sp_std::{cell::RefCell, marker::PhantomData}; use xcm::{ @@ -113,21 +114,34 @@ impl pallet_mock_liquidity_pools::Config for Runtime { type Message = MessageMock; } -impl pallet_ethereum_transaction::Config for Runtime { - type RuntimeEvent = RuntimeEvent; -} +impl pallet_ethereum_transaction::Config for Runtime {} impl pallet_mock_routers::Config for Runtime {} +pub struct MockOriginRecovery; +impl TryConvert<(Vec, Vec), DomainAddress> for MockOriginRecovery { + type Error = DispatchError; + + fn try_convert(_: (Vec, Vec)) -> Result { + Err(DispatchError::Other("Unimplemented")) + } +} + +parameter_types! { + pub Sender: AccountId32 = AccountId32::from(H256::from_low_u64_be(1).to_fixed_bytes()); +} + impl pallet_liquidity_pools_gateway::Config for Runtime { type AdminOrigin = EnsureRoot; type InboundQueue = MockLiquidityPools; type LocalEVMOrigin = EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; type Message = MessageMock; + type OriginRecovery = MockOriginRecovery; type Router = RouterMock; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; + type Sender = Sender; type WeightInfo = (); } diff --git a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs index 9e01ffc425..137160536f 100644 --- a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs +++ b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs @@ -13,37 +13,20 @@ use cfg_traits::liquidity_pools::Codec; use codec::{Decode, Encode, MaxEncodedLen}; use ethabi::{Contract, Function, Param, ParamType, Token}; use frame_support::dispatch::{DispatchError, DispatchResult}; +use frame_system::pallet_prelude::OriginFor; use scale_info::{ prelude::string::{String, ToString}, TypeInfo, }; -use sp_core::H160; +use sp_core::{bounded::BoundedVec, ConstU32, H160}; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, vec, vec::Vec}; use crate::{ AccountIdOf, EVMRouter, MessageOf, AXELAR_DESTINATION_CHAIN_PARAM, AXELAR_DESTINATION_CONTRACT_ADDRESS_PARAM, AXELAR_FUNCTION_NAME, AXELAR_PAYLOAD_PARAM, - FUNCTION_NAME, MESSAGE_PARAM, + FUNCTION_NAME, MAX_AXELAR_EVM_CHAIN_SIZE, MESSAGE_PARAM, }; -/// EVMChain holds all supported EVM chains. -#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub enum EVMChain { - Ethereum, - Goerli, -} - -/// Required due to the naming convention defined by Axelar here: -/// -impl ToString for EVMChain { - fn to_string(&self) -> String { - match self { - EVMChain::Ethereum => "Ethereum".to_string(), - EVMChain::Goerli => "ethereum-2".to_string(), - } - } -} - /// The router used for executing the LiquidityPools contract via Axelar. #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct AxelarEVMRouter @@ -52,9 +35,11 @@ where + pallet_liquidity_pools_gateway::Config + pallet_ethereum_transaction::Config + pallet_evm::Config, + OriginFor: + From + Into>>, { pub router: EVMRouter, - pub evm_chain: EVMChain, + pub evm_chain: BoundedVec>, pub liquidity_pools_contract_address: H160, pub _marker: PhantomData, } @@ -66,6 +51,8 @@ where + pallet_ethereum_transaction::Config + pallet_evm::Config, T::AccountId: AsRef<[u8; 32]>, + OriginFor: + From + Into>>, { /// Calls the init function on the EVM router. pub fn do_init(&self) -> DispatchResult { @@ -77,7 +64,7 @@ where pub fn do_send(&self, sender: AccountIdOf, msg: MessageOf) -> DispatchResult { let eth_msg = get_axelar_encoded_msg( msg.serialize(), - self.evm_chain.clone(), + self.evm_chain.clone().into_inner(), self.liquidity_pools_contract_address, ) .map_err(DispatchError::Other)?; @@ -97,9 +84,12 @@ where /// pub(crate) fn get_axelar_encoded_msg( serialized_msg: Vec, - target_chain: EVMChain, + target_chain: Vec, target_contract: H160, ) -> Result, &'static str> { + let target_chain_string = + String::from_utf8(target_chain).map_err(|_| "target chain conversion error")?; + #[allow(deprecated)] let encoded_liquidity_pools_contract = Contract { constructor: None, @@ -164,7 +154,7 @@ pub(crate) fn get_axelar_encoded_msg( .function(AXELAR_FUNCTION_NAME) .map_err(|_| "cannot retrieve Axelar contract function")? .encode_input(&[ - Token::String(target_chain.to_string()), + Token::String(target_chain_string), Token::String(target_contract.to_string()), Token::Bytes(encoded_liquidity_pools_contract), ]) diff --git a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_xcm.rs b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_xcm.rs index 3d23eda178..850dc78122 100644 --- a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_xcm.rs +++ b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_xcm.rs @@ -14,13 +14,13 @@ use cfg_traits::liquidity_pools::Codec; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::dispatch::DispatchResult; use scale_info::TypeInfo; -use sp_core::H160; +use sp_core::{bounded::BoundedVec, ConstU32, H160}; use sp_runtime::DispatchError; use sp_std::marker::PhantomData; use crate::{ - axelar_evm::get_axelar_encoded_msg, AccountIdOf, CurrencyIdOf, EVMChain, MessageOf, XCMRouter, - XcmDomain, + axelar_evm::get_axelar_encoded_msg, AccountIdOf, CurrencyIdOf, MessageOf, XCMRouter, XcmDomain, + MAX_AXELAR_EVM_CHAIN_SIZE, }; pub type AxelarXcmDomain = XcmDomain>; @@ -35,7 +35,7 @@ where + pallet_liquidity_pools_gateway::Config, { pub router: XCMRouter, - pub axelar_target_chain: EVMChain, + pub axelar_target_chain: BoundedVec>, pub axelar_target_contract: H160, pub _marker: PhantomData, } @@ -56,7 +56,7 @@ where pub fn do_send(&self, sender: AccountIdOf, msg: MessageOf) -> DispatchResult { let contract_call = get_axelar_encoded_msg( msg.serialize(), - self.axelar_target_chain.clone(), + self.axelar_target_chain.clone().into_inner(), self.axelar_target_contract, ) .map_err(|_| DispatchError::Other("encoded contract call retrieval"))?; diff --git a/pallets/liquidity-pools-gateway/routers/src/tests.rs b/pallets/liquidity-pools-gateway/routers/src/tests.rs index f22e88f3f5..53fe01e991 100644 --- a/pallets/liquidity-pools-gateway/routers/src/tests.rs +++ b/pallets/liquidity-pools-gateway/routers/src/tests.rs @@ -1,13 +1,14 @@ use ::xcm::{ lts::WeightLimit, v2::OriginKind, - v3::{Instruction::*, MultiAsset, Weight}, + v3::{Instruction::*, MultiAsset}, }; use cfg_mocks::MessageMock; use cfg_primitives::CFG; use cfg_traits::liquidity_pools::{Codec, Router}; use cumulus_primitives_core::MultiLocation; use frame_support::{assert_noop, assert_ok, traits::fungible::Mutate}; +use lazy_static::lazy_static; use pallet_evm::AddressMapping; use sp_core::{bounded_vec, crypto::AccountId32, H160, H256, U256}; use sp_runtime::{ @@ -18,6 +19,14 @@ use sp_runtime::{ use super::mock::*; use crate::*; +lazy_static! { + static ref TEST_EVM_CHAIN: BoundedVec> = + BoundedVec::>::try_from( + "ethereum".as_bytes().to_vec() + ) + .unwrap(); +} + mod evm_router { use util::*; @@ -193,8 +202,10 @@ mod xcm_router { ethereum_xcm_transact_call_index: bounded_vec![0], contract_address: H160::from_slice([0; 20].as_slice()), max_gas_limit: 10, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id.clone(), - fee_per_second: 1u128, + fee_amount: 200000000000000000, }; let sender: AccountId32 = [0; 32].into(); @@ -247,24 +258,11 @@ mod xcm_router { let sent_messages = sent_xcm(); assert_eq!(sent_messages.len(), 1); - let transact_weight = Weight::from_parts( - test_data.xcm_domain.max_gas_limit * 25_000, - DEFAULT_PROOF_SIZE.saturating_div(2), - ); - - let overall_weight = Weight::from_parts( - transact_weight.ref_time() + XCM_INSTRUCTION_WEIGHT * 3, - DEFAULT_PROOF_SIZE, - ); - - let fees = Into::::into(overall_weight.ref_time()) - * test_data.xcm_domain.fee_per_second; - let (_, xcm) = sent_messages.first().unwrap(); assert!(xcm.0.contains(&WithdrawAsset( (MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }) .into() ))); @@ -272,9 +270,9 @@ mod xcm_router { assert!(xcm.0.contains(&BuyExecution { fees: MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }, - weight_limit: WeightLimit::Limited(overall_weight), + weight_limit: WeightLimit::Limited(test_data.xcm_domain.overall_weight), })); let expected_call = get_encoded_ethereum_xcm_call::( @@ -285,7 +283,7 @@ mod xcm_router { assert!(xcm.0.contains(&Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: transact_weight, + require_weight_at_most: test_data.xcm_domain.transact_required_weight_at_most, call: expected_call.into(), })); }); @@ -306,29 +304,6 @@ mod xcm_router { assert_ok!(router.do_send(test_data.sender, test_data.msg)); }); } - - #[test] - fn transactor_info_not_set() { - new_test_ext().execute_with(|| { - let test_data = get_test_data(); - - let router = XCMRouter:: { - xcm_domain: test_data.xcm_domain.clone(), - _marker: Default::default(), - }; - - // Manually insert the fee per second in the `DestinationAssetFeePerSecond` - // storage. - - pallet_xcm_transactor::DestinationAssetFeePerSecond::::insert( - test_data.dest, - test_data.xcm_domain.fee_per_second.clone(), - ); - - // We ensure we can send although no `TransactInfo is set` - assert_ok!(router.do_send(test_data.sender, test_data.msg),); - }); - } } } @@ -408,7 +383,7 @@ mod axelar_evm { evm_domain: test_data.evm_domain, _marker: Default::default(), }, - evm_chain: EVMChain::Ethereum, + evm_chain: TEST_EVM_CHAIN.clone(), liquidity_pools_contract_address: test_data .liquidity_pools_contract_address, _marker: Default::default(), @@ -429,7 +404,7 @@ mod axelar_evm { evm_domain: test_data.evm_domain, _marker: Default::default(), }, - evm_chain: EVMChain::Ethereum, + evm_chain: TEST_EVM_CHAIN.clone(), liquidity_pools_contract_address: test_data .liquidity_pools_contract_address, _marker: Default::default(), @@ -475,7 +450,7 @@ mod axelar_evm { evm_domain: test_data.evm_domain, _marker: Default::default(), }, - evm_chain: EVMChain::Ethereum, + evm_chain: TEST_EVM_CHAIN.clone(), liquidity_pools_contract_address: test_data .liquidity_pools_contract_address, _marker: Default::default(), @@ -496,7 +471,7 @@ mod axelar_evm { evm_domain: test_data.evm_domain, _marker: Default::default(), }, - evm_chain: EVMChain::Ethereum, + evm_chain: TEST_EVM_CHAIN.clone(), liquidity_pools_contract_address: test_data .liquidity_pools_contract_address, _marker: Default::default(), @@ -525,7 +500,7 @@ mod axelar_xcm { pub currency_id: CurrencyId, pub dest: MultiLocation, pub xcm_domain: XcmDomain<::CurrencyId>, - pub axelar_target_chain: EVMChain, + pub axelar_target_chain: BoundedVec>, pub axelar_target_contract: H160, pub sender: AccountId32, pub msg: MessageMock, @@ -540,10 +515,12 @@ mod axelar_xcm { ethereum_xcm_transact_call_index: bounded_vec![0], contract_address: H160::from_slice([0; 20].as_slice()), max_gas_limit: 10, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id.clone(), - fee_per_second: 1u128, + fee_amount: 200000000000000000, }; - let axelar_target_chain = EVMChain::Ethereum; + let axelar_target_chain = TEST_EVM_CHAIN.clone(); let axelar_target_contract = H160::from_low_u64_be(1); let sender: AccountId32 = [0; 32].into(); @@ -612,24 +589,14 @@ mod axelar_xcm { let sent_messages = sent_xcm(); assert_eq!(sent_messages.len(), 1); - let transact_weight = Weight::from_parts( - test_data.xcm_domain.max_gas_limit * 25_000, - DEFAULT_PROOF_SIZE.saturating_div(2), - ); - - let overall_weight = Weight::from_parts( - transact_weight.ref_time() + XCM_INSTRUCTION_WEIGHT * 3, - DEFAULT_PROOF_SIZE, - ); - - let fees = Into::::into(overall_weight.ref_time()) - * test_data.xcm_domain.fee_per_second; + let sent_messages = sent_xcm(); + assert_eq!(sent_messages.len(), 1); let (_, xcm) = sent_messages.first().unwrap(); assert!(xcm.0.contains(&WithdrawAsset( (MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }) .into() ))); @@ -637,18 +604,17 @@ mod axelar_xcm { assert!(xcm.0.contains(&BuyExecution { fees: MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }, - weight_limit: WeightLimit::Limited(overall_weight), + weight_limit: WeightLimit::Limited(test_data.xcm_domain.overall_weight), })); let contract_call = get_axelar_encoded_msg( test_data.msg.serialize(), - test_data.axelar_target_chain.clone(), + test_data.axelar_target_chain.clone().into_inner(), test_data.axelar_target_contract, ) .unwrap(); - let expected_call = get_encoded_ethereum_xcm_call::( test_data.xcm_domain.clone(), contract_call, @@ -657,40 +623,11 @@ mod axelar_xcm { assert!(xcm.0.contains(&Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: transact_weight, + require_weight_at_most: test_data.xcm_domain.transact_required_weight_at_most, call: expected_call.into(), })); }); } - - #[test] - fn transactor_info_not_set() { - new_test_ext().execute_with(|| { - let test_data = get_test_data(); - - let domain_router = - DomainRouter::::AxelarXCM(AxelarXCMRouter:: { - router: XCMRouter { - xcm_domain: test_data.xcm_domain.clone(), - _marker: Default::default(), - }, - axelar_target_chain: test_data.axelar_target_chain, - axelar_target_contract: test_data.axelar_target_contract, - _marker: Default::default(), - }); - - // Manually insert the fee per second in the `DestinationAssetFeePerSecond` - // storage. - - pallet_xcm_transactor::DestinationAssetFeePerSecond::::insert( - test_data.dest, - test_data.xcm_domain.fee_per_second.clone(), - ); - - // We ensure we can send although no `TransactInfo is set` - assert_ok!(domain_router.send(test_data.sender, test_data.msg),); - }); - } } } @@ -706,7 +643,7 @@ mod ethereum_xcm { pub currency_id: CurrencyId, pub dest: MultiLocation, pub xcm_domain: XcmDomain<::CurrencyId>, - pub axelar_target_chain: EVMChain, + pub axelar_target_chain: BoundedVec>, pub axelar_target_contract: H160, pub sender: AccountId32, pub msg: MessageMock, @@ -721,10 +658,12 @@ mod ethereum_xcm { ethereum_xcm_transact_call_index: bounded_vec![0], contract_address: H160::from_slice([0; 20].as_slice()), max_gas_limit: 10, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id.clone(), - fee_per_second: 1u128, + fee_amount: 200000000000000000, }; - let axelar_target_chain = EVMChain::Ethereum; + let axelar_target_chain = TEST_EVM_CHAIN.clone(); let axelar_target_contract = H160::from_low_u64_be(1); let sender: AccountId32 = [0; 32].into(); @@ -789,24 +728,11 @@ mod ethereum_xcm { let sent_messages = sent_xcm(); assert_eq!(sent_messages.len(), 1); - let transact_weight = Weight::from_parts( - test_data.xcm_domain.max_gas_limit * 25_000, - DEFAULT_PROOF_SIZE.saturating_div(2), - ); - - let overall_weight = Weight::from_parts( - transact_weight.ref_time() + XCM_INSTRUCTION_WEIGHT * 3, - DEFAULT_PROOF_SIZE, - ); - - let fees = Into::::into(overall_weight.ref_time()) - * test_data.xcm_domain.fee_per_second; - let (_, xcm) = sent_messages.first().unwrap(); assert!(xcm.0.contains(&WithdrawAsset( (MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }) .into() ))); @@ -814,9 +740,9 @@ mod ethereum_xcm { assert!(xcm.0.contains(&BuyExecution { fees: MultiAsset { id: ::xcm::v3::AssetId::Concrete(MultiLocation::here()), - fun: ::xcm::v3::Fungibility::Fungible(fees), + fun: ::xcm::v3::Fungibility::Fungible(test_data.xcm_domain.fee_amount), }, - weight_limit: WeightLimit::Limited(overall_weight), + weight_limit: WeightLimit::Limited(test_data.xcm_domain.overall_weight), })); let contract_call = get_encoded_contract_call(test_data.msg.serialize()).unwrap(); @@ -828,37 +754,10 @@ mod ethereum_xcm { assert!(xcm.0.contains(&Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: transact_weight, + require_weight_at_most: test_data.xcm_domain.transact_required_weight_at_most, call: expected_call.into(), })); }); } - - #[test] - fn transactor_info_not_set() { - new_test_ext().execute_with(|| { - let test_data = get_test_data(); - - let domain_router = - DomainRouter::::EthereumXCM(EthereumXCMRouter:: { - router: XCMRouter { - xcm_domain: test_data.xcm_domain.clone(), - _marker: Default::default(), - }, - _marker: Default::default(), - }); - - // Manually insert the fee per second in the `DestinationAssetFeePerSecond` - // storage. - - pallet_xcm_transactor::DestinationAssetFeePerSecond::::insert( - test_data.dest, - test_data.xcm_domain.fee_per_second.clone(), - ); - - // We ensure we can send although no `TransactInfo is set` - assert_ok!(domain_router.send(test_data.sender, test_data.msg),); - }); - } } } diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 293c8777e5..10bb679c98 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -13,13 +13,16 @@ use core::fmt::Debug; -use cfg_traits::liquidity_pools::{Codec, InboundQueue, OutboundQueue, Router as DomainRouter}; +use cfg_traits::{ + liquidity_pools::{Codec, InboundQueue, OutboundQueue, Router as DomainRouter}, + TryConvert, +}; use cfg_types::domain_address::{Domain, DomainAddress}; use codec::{EncodeLike, FullCodec}; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; use frame_system::pallet_prelude::OriginFor; pub use pallet::*; -use sp_std::convert::TryInto; +use sp_std::{convert::TryInto, vec::Vec}; use crate::weights::WeightInfo; @@ -36,6 +39,8 @@ mod tests; #[frame_support::pallet] pub mod pallet { + const BYTES_U32: usize = 4; + use super::*; #[pallet::pallet] @@ -58,7 +63,7 @@ pub mod pallet { /// local context i.e. a different pallet. type LocalEVMOrigin: EnsureOrigin< ::RuntimeOrigin, - Success = DomainAddress, + Success = GatewayOrigin, >; /// The AdminOrigin ensures that some calls can only be performed by @@ -69,7 +74,7 @@ pub mod pallet { /// /// NOTE - this `Codec` trait is the Centrifuge trait for liquidity /// pools' messages. - type Message: Codec; + type Message: Codec + Clone; /// The message router type that is stored for each domain. type Router: DomainRouter @@ -84,11 +89,19 @@ pub mod pallet { /// The type that processes incoming messages. type InboundQueue: InboundQueue; + /// A way to recover a domain address from two byte slices + type OriginRecovery: TryConvert<(Vec, Vec), DomainAddress, Error = DispatchError>; + type WeightInfo: WeightInfo; /// Maximum size of an incoming message. #[pallet::constant] type MaxIncomingMessageSize: Get; + + /// The sender account that will be used in the OutboundQueue + /// implementation. + #[pallet::constant] + type Sender: Get; } #[pallet::event] @@ -102,6 +115,19 @@ pub mod pallet { /// An instance was removed from a domain. InstanceRemoved { instance: DomainAddress }, + + /// A relayer was added. + RelayerAdded { relayer: DomainAddress }, + + /// A relayer was removed. + RelayerRemoved { relayer: DomainAddress }, + + /// An outbound message has been submitted. + OutboundMessageSubmitted { + sender: T::AccountId, + message: Vec, + domain: Domain, + }, } /// Storage for domain routers. @@ -115,15 +141,18 @@ pub mod pallet { /// /// This can only be modified by an admin. #[pallet::storage] - pub(crate) type Allowlist = StorageDoubleMap< - _, - Blake2_128Concat, - Domain, - Blake2_128Concat, - DomainAddress, - (), - ValueQuery, - >; + #[pallet::getter(fn allowlist)] + pub(crate) type Allowlist = + StorageDoubleMap<_, Blake2_128Concat, Domain, Blake2_128Concat, DomainAddress, ()>; + + /// Storage that contains a limited number of whitelisted instances of + /// deployed liquidity pools for a particular domain. + /// + /// This can only be modified by an admin. + #[pallet::storage] + #[pallet::getter(fn relayer)] + pub(crate) type RelayerList = + StorageDoubleMap<_, Blake2_128Concat, Domain, Blake2_128Concat, DomainAddress, ()>; #[pallet::error] pub enum Error { @@ -142,14 +171,27 @@ pub mod pallet { /// Instance was already added to the domain. InstanceAlreadyAdded, + /// Relayer was already added to the domain + RelayerAlreadyAdded, + /// Maximum number of instances for a domain was reached. MaxDomainInstances, /// Unknown instance. UnknownInstance, + /// Unknown relayer + UnknownRelayer, + /// Router not found. RouterNotFound, + + /// Relayer messages need to prepend the with + /// the original source chain and source address + /// that triggered the message. + /// Decoding that is essential and this error + /// signals malforming of the wrapping information. + RelayerMessageDecodingFailed, } #[pallet::call] @@ -199,7 +241,7 @@ pub mod pallet { Ok(()) } - /// Remove a instance from a specific domain. + /// Remove an instance from a specific domain. #[pallet::weight(T::WeightInfo::remove_instance())] #[pallet::call_index(2)] pub fn remove_instance(origin: OriginFor, instance: DomainAddress) -> DispatchResult { @@ -217,37 +259,170 @@ pub mod pallet { Ok(()) } + /// Add a known instance of a deployed liquidity pools integration for a + /// specific domain. + #[pallet::weight(T::WeightInfo::add_relayer())] + #[pallet::call_index(3)] + pub fn add_relayer(origin: OriginFor, relayer: DomainAddress) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + ensure!( + relayer.domain() != Domain::Centrifuge, + Error::::DomainNotSupported + ); + + ensure!( + !RelayerList::::contains_key(relayer.domain(), relayer.clone()), + Error::::RelayerAlreadyAdded, + ); + + RelayerList::::insert(relayer.domain(), relayer.clone(), ()); + + Self::deposit_event(Event::RelayerAdded { relayer }); + + Ok(()) + } + + /// Remove an instance from a specific domain. + #[pallet::weight(T::WeightInfo::remove_relayer())] + #[pallet::call_index(4)] + pub fn remove_relayer(origin: OriginFor, relayer: DomainAddress) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin.clone())?; + + ensure!( + RelayerList::::contains_key(relayer.domain(), relayer.clone()), + Error::::UnknownRelayer, + ); + + RelayerList::::remove(relayer.domain(), relayer.clone()); + + Self::deposit_event(Event::RelayerRemoved { relayer }); + + Ok(()) + } + /// Process an incoming message. #[pallet::weight(0)] - #[pallet::call_index(3)] + #[pallet::call_index(5)] pub fn process_msg( origin: OriginFor, msg: BoundedVec, ) -> DispatchResult { - let domain_address = T::LocalEVMOrigin::ensure_origin(origin)?; - - match domain_address { - DomainAddress::EVM(_, _) => { + let (domain_address, incoming_msg) = match T::LocalEVMOrigin::ensure_origin(origin)? { + GatewayOrigin::Domain(domain_address) => { + Pallet::::validate(domain_address, msg)? + } + GatewayOrigin::AxelarRelay(domain_address) => { + // Every axelar relay address has a separate storage ensure!( - Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - ), - Error::::UnknownInstance, + RelayerList::::contains_key(domain_address.domain(), domain_address), + Error::::UnknownRelayer ); - let incoming_msg = T::Message::deserialize(&mut msg.as_slice()) - .map_err(|_| Error::::MessageDecodingFailed)?; - - T::InboundQueue::submit(domain_address, incoming_msg) + // Every axelar relay will prepend the (sourceChain, + // sourceAddress) from actual origination chain to the + // message bytes, with a length identifier + let slice_ref = &mut msg.as_slice(); + let length_source_chain: usize = + Pallet::::try_range(slice_ref, BYTES_U32, |be_bytes_u32| { + let mut bytes = [0u8; BYTES_U32]; + // NOTE: This can NEVER panic as the `try_range` logic ensures the given + // bytes have the right length. I.e. 4 in this case + bytes.copy_from_slice(be_bytes_u32); + + u32::from_be_bytes(bytes).try_into().map_err(|_| { + DispatchError::Other("Expect: usize in wasm is always ge u32") + }) + })?; + + let source_chain = + Pallet::::try_range(slice_ref, length_source_chain, |source_chain| { + Ok(source_chain.to_vec()) + })?; + + let length_source_address: usize = + Pallet::::try_range(slice_ref, BYTES_U32, |be_bytes_u32| { + let mut bytes = [0u8; BYTES_U32]; + // NOTE: This can NEVER panic as the `try_range` logic ensures the given + // bytes have the right length. I.e. 4 in this case + bytes.copy_from_slice(be_bytes_u32); + + u32::from_be_bytes(bytes).try_into().map_err(|_| { + DispatchError::Other("Expect: usize in wasm is always ge u32") + }) + })?; + + let source_address = + Pallet::::try_range(slice_ref, length_source_address, |source_chain| { + Ok(source_chain.to_vec()) + })?; + + let origin_msg = Pallet::::try_range(slice_ref, slice_ref.len(), |msg| { + BoundedVec::try_from(msg.to_vec()).map_err(|_| { + DispatchError::Other( + "Remaining bytes smaller vector in the first place. qed.", + ) + }) + })?; + + let origin_domain = + T::OriginRecovery::try_convert((source_chain, source_address))?; + + Pallet::::validate(origin_domain, origin_msg)? } - DomainAddress::Centrifuge(_) => Err(Error::::InvalidMessageOrigin.into()), + }; + + T::InboundQueue::submit(domain_address, incoming_msg) + } + } + + impl Pallet { + pub(crate) fn try_range<'a, D, F>( + slice: &mut &'a [u8], + next_steps: usize, + transformer: F, + ) -> Result + where + F: Fn(&'a [u8]) -> Result, + { + ensure!( + slice.len() >= next_steps, + Error::::RelayerMessageDecodingFailed + ); + + let (input, new_slice) = slice.split_at(next_steps); + let res = transformer(input)?; + *slice = new_slice; + + Ok(res) + } + + fn validate( + address: DomainAddress, + msg: BoundedVec, + ) -> Result<(DomainAddress, T::Message), DispatchError> { + if let DomainAddress::Centrifuge(_) = address { + return Err(Error::::InvalidMessageOrigin.into()); } + + ensure!( + Allowlist::::contains_key(address.domain(), address.clone()), + Error::::UnknownInstance, + ); + + let incoming_msg = T::Message::deserialize(&mut msg.as_slice()) + .map_err(|_| Error::::MessageDecodingFailed)?; + + Ok((address, incoming_msg)) } } /// This pallet will be the `OutboundQueue` used by other pallets to send /// outgoing messages. + /// + /// NOTE - the sender provided as an argument is not used at the moment, we + /// are using the sender specified in the pallet config so that we can + /// ensure that the account is funded. impl OutboundQueue for Pallet { type Destination = Domain; type Message = T::Message; @@ -263,9 +438,18 @@ pub mod pallet { Error::::DomainNotSupported ); - let router = DomainRouters::::get(destination).ok_or(Error::::RouterNotFound)?; + let router = + DomainRouters::::get(destination.clone()).ok_or(Error::::RouterNotFound)?; + + router.send(T::Sender::get(), msg.clone())?; - router.send(sender, msg) + Self::deposit_event(Event::OutboundMessageSubmitted { + sender, + message: msg.serialize(), + domain: destination, + }); + + Ok(()) } } } diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 5b1bcbc29f..aea481f4a8 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -1,10 +1,14 @@ -use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_routers, MessageMock, RouterMock}; +use cfg_mocks::{ + pallet_mock_liquidity_pools, pallet_mock_routers, pallet_mock_try_convert, MessageMock, + RouterMock, +}; use cfg_types::domain_address::DomainAddress; use frame_system::EnsureRoot; use sp_core::{crypto::AccountId32, ConstU16, ConstU32, ConstU64, H256}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, + DispatchError, }; use crate::{pallet as pallet_liquidity_pools_gateway, EnsureLocal}; @@ -14,6 +18,13 @@ pub type Balance = u128; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; +pub const LENGTH_SOURCE_CHAIN: usize = 8; +pub const SOURCE_CHAIN: [u8; LENGTH_SOURCE_CHAIN] = *b"ethereum"; +pub const SOURCE_CHAIN_EVM_ID: u64 = 1; + +pub const LENGTH_SOURCE_ADDRESS: usize = 20; +pub const SOURCE_ADDRESS: [u8; LENGTH_SOURCE_ADDRESS] = [0u8; LENGTH_SOURCE_ADDRESS]; + frame_support::construct_runtime!( pub enum Runtime where Block = Block, @@ -24,6 +35,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, MockLiquidityPools: pallet_mock_liquidity_pools, MockRouters: pallet_mock_routers, + MockOriginRecovery: pallet_mock_try_convert, LiquidityPoolsGateway: pallet_liquidity_pools_gateway, } ); @@ -78,15 +90,27 @@ 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; + type From = (Vec, Vec); + type To = DomainAddress; +} + +frame_support::parameter_types! { + pub Sender: AccountId32 = AccountId32::from(H256::from_low_u64_be(1).to_fixed_bytes()); +} + impl pallet_liquidity_pools_gateway::Config for Runtime { type AdminOrigin = EnsureRoot; type InboundQueue = MockLiquidityPools; type LocalEVMOrigin = EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; type Message = MessageMock; + type OriginRecovery = MockOriginRecovery; type Router = RouterMock; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; + type Sender = Sender; type WeightInfo = (); } diff --git a/pallets/liquidity-pools-gateway/src/origin.rs b/pallets/liquidity-pools-gateway/src/origin.rs index ad5408b016..1d2d18e174 100644 --- a/pallets/liquidity-pools-gateway/src/origin.rs +++ b/pallets/liquidity-pools-gateway/src/origin.rs @@ -20,23 +20,22 @@ use sp_runtime::RuntimeDebug; #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub enum GatewayOrigin { - Local(DomainAddress), + Domain(DomainAddress), + AxelarRelay(DomainAddress), } pub struct EnsureLocal; impl> + From> EnsureOrigin for EnsureLocal { - type Success = DomainAddress; + type Success = GatewayOrigin; fn try_origin(o: O) -> Result { - o.into().map(|o| match o { - GatewayOrigin::Local(domain_address) => domain_address, - }) + o.into() } #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result { - Ok(O::from(GatewayOrigin::Local(DomainAddress::EVM( + Ok(O::from(GatewayOrigin::Domain(DomainAddress::EVM( 1, H160::from_low_u64_be(1).into(), )))) diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 17459924bc..11f8076b9b 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -10,6 +10,7 @@ use super::{ origin::*, pallet::*, }; +use crate::pallet; mod utils { use super::*; @@ -28,6 +29,73 @@ mod utils { use utils::*; +mod pallet_internals { + + use super::*; + + #[test] + fn try_range_fails_if_slice_to_short() { + new_test_ext().execute_with(|| { + let three_bytes = [0u8; 3]; + let steps = 4usize; + + assert_noop!( + Pallet::::try_range(&mut three_bytes.as_slice(), steps, |_| Ok(())), + Error::::RelayerMessageDecodingFailed + ); + }) + } + + #[test] + fn try_range_updates_slice_ref_correctly() { + new_test_ext().execute_with(|| { + let bytes = [1, 2, 3, 4, 5, 6, 7u8]; + let slice = &mut bytes.as_slice(); + let steps = 4; + let first_section = + Pallet::::try_range(slice, steps, |first_section| Ok(first_section)) + .expect("Slice is long enough"); + + assert_eq!(first_section, &[1, 2, 3, 4]); + + let steps = 2; + let second_section = + Pallet::::try_range(slice, steps, |second_section| Ok(second_section)) + .expect("Slice is long enough"); + + assert_eq!(&second_section, &[5, 6]); + + let steps = 1; + let third_section = + Pallet::::try_range(slice, steps, |third_section| Ok(third_section)) + .expect("Slice is long enough"); + + assert_eq!(&third_section, &[7]); + }) + } + + #[test] + fn try_range_does_not_update_slice_if_transformer_errors() { + new_test_ext().execute_with(|| { + let bytes = [1, 2, 3, 4, 5, 6, 7u8]; + let slice = &mut bytes.as_slice(); + let steps = 4; + let first_section = + Pallet::::try_range(slice, steps, |first_section| Ok(first_section)) + .expect("Slice is long enough"); + + assert_eq!(first_section, &[1, 2, 3, 4]); + + let steps = 1; + assert!(Pallet::::try_range(slice, steps, |_| Err::<(), _>( + DispatchError::Corruption + )) + .is_err()); + assert_eq!(slice, &[5, 6, 7]); + }) + } +} + mod set_domain_router { use super::*; @@ -259,7 +327,247 @@ mod remove_instance { } } -mod process_msg { +mod process_msg_axelar_relay { + use sp_core::bounded::BoundedVec; + + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(SOURCE_CHAIN_EVM_ID, SOURCE_ADDRESS); + let relayer_address = DomainAddress::EVM(0, address.into()); + + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); + + assert_ok!(LiquidityPoolsGateway::add_relayer( + RuntimeOrigin::root(), + relayer_address.clone(), + )); + + let expected_msg = MessageMock::First; + let expected_domain_address = domain_address.clone(); + + let mut msg = Vec::new(); + msg.extend_from_slice(&(LENGTH_SOURCE_CHAIN as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_CHAIN); + msg.extend_from_slice(&(LENGTH_SOURCE_ADDRESS as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_ADDRESS); + msg.extend_from_slice(&expected_msg.serialize()); + + MockLiquidityPools::mock_submit(move |domain, message| { + assert_eq!(domain, expected_domain_address); + assert_eq!(message, expected_msg); + Ok(()) + }); + + let expected_domain_address = domain_address.clone(); + + MockOriginRecovery::mock_try_convert(move |origin| { + let (source_chain, source_address) = origin; + + assert_eq!(&source_chain, SOURCE_CHAIN.as_slice()); + assert_eq!(&source_address, SOURCE_ADDRESS.as_slice()); + + Ok(expected_domain_address.clone()) + }); + + assert_ok!(LiquidityPoolsGateway::process_msg( + GatewayOrigin::AxelarRelay(relayer_address).into(), + BoundedVec::::try_from(msg).unwrap() + )); + }); + } + + #[test] + fn invalid_message_origin() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); + let relayer_address = DomainAddress::EVM(0, address.into()); + + assert_ok!(LiquidityPoolsGateway::add_relayer( + RuntimeOrigin::root(), + relayer_address.clone(), + )); + + let expected_msg = MessageMock::First; + + let mut msg = Vec::new(); + // Need to prepend length signaler + msg.extend_from_slice(&(0 as u32).to_be_bytes()); + msg.extend_from_slice(&(0 as u32).to_be_bytes()); + msg.extend_from_slice(&expected_msg.serialize()); + + MockOriginRecovery::mock_try_convert(move |origin| { + let (source_chain, source_address) = origin; + + assert!(source_chain.is_empty()); + assert!(source_address.is_empty()); + + Ok(domain_address.clone()) + }); + + assert_noop!( + LiquidityPoolsGateway::process_msg( + GatewayOrigin::AxelarRelay(relayer_address).into(), + BoundedVec::::try_from(msg).unwrap() + ), + Error::::InvalidMessageOrigin, + ); + }); + } + + #[test] + fn unknown_instance() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(SOURCE_CHAIN_EVM_ID, SOURCE_ADDRESS); + let relayer_address = DomainAddress::EVM(0, address.into()); + + assert_ok!(LiquidityPoolsGateway::add_relayer( + RuntimeOrigin::root(), + relayer_address.clone(), + )); + + let expected_msg = MessageMock::First; + + let mut msg = Vec::new(); + msg.extend_from_slice(&(LENGTH_SOURCE_CHAIN as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_CHAIN); + msg.extend_from_slice(&(LENGTH_SOURCE_ADDRESS as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_ADDRESS); + msg.extend_from_slice(&expected_msg.serialize()); + + let expected_domain_address = domain_address.clone(); + + MockOriginRecovery::mock_try_convert(move |origin| { + let (source_chain, source_address) = origin; + + assert_eq!(&source_chain, SOURCE_CHAIN.as_slice()); + assert_eq!(&source_address, SOURCE_ADDRESS.as_slice()); + + Ok(expected_domain_address.clone()) + }); + + assert_noop!( + LiquidityPoolsGateway::process_msg( + GatewayOrigin::AxelarRelay(relayer_address).into(), + BoundedVec::::try_from(msg).unwrap() + ), + Error::::UnknownInstance + ); + }); + } + + #[test] + fn message_decode() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(SOURCE_CHAIN_EVM_ID, SOURCE_ADDRESS); + let relayer_address = DomainAddress::EVM(0, address.into()); + + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); + + assert_ok!(LiquidityPoolsGateway::add_relayer( + RuntimeOrigin::root(), + relayer_address.clone(), + )); + + let encoded_msg: Vec = vec![11]; + let mut msg = Vec::new(); + msg.extend_from_slice(&(LENGTH_SOURCE_CHAIN as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_CHAIN); + msg.extend_from_slice(&(LENGTH_SOURCE_ADDRESS as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_ADDRESS); + msg.extend_from_slice(&encoded_msg); + + let expected_domain_address = domain_address.clone(); + + MockOriginRecovery::mock_try_convert(move |origin| { + let (source_chain, source_address) = origin; + + assert_eq!(&source_chain, SOURCE_CHAIN.as_slice()); + assert_eq!(&source_address, SOURCE_ADDRESS.as_slice()); + + Ok(expected_domain_address.clone()) + }); + + assert_noop!( + LiquidityPoolsGateway::process_msg( + GatewayOrigin::Domain(domain_address).into(), + BoundedVec::::try_from(encoded_msg).unwrap() + ), + Error::::MessageDecodingFailed, + ); + }); + } + + #[test] + fn liquidity_pools_error() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(SOURCE_CHAIN_EVM_ID, SOURCE_ADDRESS); + let relayer_address = DomainAddress::EVM(0, address.into()); + + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); + + assert_ok!(LiquidityPoolsGateway::add_relayer( + RuntimeOrigin::root(), + relayer_address.clone(), + )); + + let expected_msg = MessageMock::First; + + let mut msg = Vec::new(); + msg.extend_from_slice(&(LENGTH_SOURCE_CHAIN as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_CHAIN); + msg.extend_from_slice(&(LENGTH_SOURCE_ADDRESS as u32).to_be_bytes()); + msg.extend_from_slice(&SOURCE_ADDRESS); + msg.extend_from_slice(&expected_msg.serialize()); + + let expected_domain_address = domain_address.clone(); + + MockOriginRecovery::mock_try_convert(move |origin| { + let (source_chain, source_address) = origin; + + assert_eq!(&source_chain, SOURCE_CHAIN.as_slice()); + assert_eq!(&source_address, SOURCE_ADDRESS.as_slice()); + + Ok(expected_domain_address.clone()) + }); + + let err = sp_runtime::DispatchError::from("liquidity_pools error"); + let expected_domain_address = domain_address.clone(); + + MockLiquidityPools::mock_submit(move |domain, message| { + assert_eq!(domain, expected_domain_address.clone()); + assert_eq!(message, expected_msg); + Err(err) + }); + + assert_noop!( + LiquidityPoolsGateway::process_msg( + GatewayOrigin::Domain(domain_address).into(), + BoundedVec::::try_from(msg).unwrap() + ), + err, + ); + }); + } +} + +mod process_msg_domain { use sp_core::bounded::BoundedVec; use super::*; @@ -287,7 +595,7 @@ mod process_msg { }); assert_ok!(LiquidityPoolsGateway::process_msg( - GatewayOrigin::Local(domain_address).into(), + GatewayOrigin::Domain(domain_address).into(), BoundedVec::::try_from(encoded_msg).unwrap() )); }); @@ -316,7 +624,7 @@ mod process_msg { assert_noop!( LiquidityPoolsGateway::process_msg( - GatewayOrigin::Local(domain_address).into(), + GatewayOrigin::Domain(domain_address).into(), BoundedVec::::try_from(encoded_msg).unwrap() ), Error::::InvalidMessageOrigin, @@ -333,7 +641,7 @@ mod process_msg { assert_noop!( LiquidityPoolsGateway::process_msg( - GatewayOrigin::Local(domain_address).into(), + GatewayOrigin::Domain(domain_address).into(), BoundedVec::::try_from(encoded_msg).unwrap() ), Error::::UnknownInstance, @@ -356,7 +664,7 @@ mod process_msg { assert_noop!( LiquidityPoolsGateway::process_msg( - GatewayOrigin::Local(domain_address).into(), + GatewayOrigin::Domain(domain_address).into(), BoundedVec::::try_from(encoded_msg).unwrap() ), Error::::MessageDecodingFailed, @@ -390,7 +698,7 @@ mod process_msg { assert_noop!( LiquidityPoolsGateway::process_msg( - GatewayOrigin::Local(domain_address).into(), + GatewayOrigin::Domain(domain_address).into(), BoundedVec::::try_from(encoded_msg).unwrap() ), err, @@ -419,11 +727,10 @@ mod outbound_queue_impl { let msg = MessageMock::First; router.mock_send({ - let sender = sender.clone(); let msg = msg.clone(); move |mock_sender, mock_msg| { - assert_eq!(sender, mock_sender); + assert_eq!(::Sender::get(), mock_sender); assert_eq!(msg, mock_msg); Ok(()) @@ -452,11 +759,10 @@ mod outbound_queue_impl { let expected_error = DispatchError::Other("router error"); router.mock_send({ - let sender = sender.clone(); let msg = msg.clone(); move |mock_sender, mock_msg| { - assert_eq!(sender, mock_sender); + assert_eq!(::Sender::get(), mock_sender); assert_eq!(msg, mock_msg); Err(expected_error) diff --git a/pallets/liquidity-pools-gateway/src/weights.rs b/pallets/liquidity-pools-gateway/src/weights.rs index c9548a6acf..c83bec47fe 100644 --- a/pallets/liquidity-pools-gateway/src/weights.rs +++ b/pallets/liquidity-pools-gateway/src/weights.rs @@ -10,29 +10,91 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use frame_support::weights::Weight; +use frame_support::weights::{constants::RocksDbWeight, Weight}; pub trait WeightInfo { fn set_domain_router() -> Weight; fn add_instance() -> Weight; fn remove_instance() -> Weight; + fn add_relayer() -> Weight; + fn remove_relayer() -> Weight; fn process_msg() -> Weight; } +// NOTE: We use temporary weights here. `execute_epoch` is by far our heaviest +// extrinsic. N denotes the number of tranches. 4 is quite heavy and +// should be enough. +const N: u64 = 4; + impl WeightInfo for () { fn set_domain_router() -> Weight { - Weight::from_ref_time(10_000_000) + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } fn add_instance() -> Weight { - Weight::from_ref_time(10_000_000) + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } fn remove_instance() -> Weight { - Weight::from_ref_time(10_000_000) + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + fn add_relayer() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + fn remove_relayer() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(17_000_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } fn process_msg() -> Weight { - Weight::from_ref_time(10_000_000) + // TODO: BENCHMARK AND USE REAL WEIGHTS + // + // NOTE: For reference this weight compared to our maximum weight + // * This weight { ref_time: 4333558693, proof_size: 91070 } + // * Maximum weight { ref_time: 500000000000, proof_size: 5242880 } + // + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } } diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 8525bbdeef..ed633d3610 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -63,7 +63,7 @@ use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert}, FixedPointNumber, SaturatedConversion, }; -use sp_std::{convert::TryInto, vec, vec::Vec}; +use sp_std::{convert::TryInto, vec}; use xcm::{ latest::NetworkId, prelude::{AccountKey20, GlobalConsensus, PalletInstance, X3}, @@ -99,7 +99,7 @@ pub type MessageOf = Message< ::PoolId, ::TrancheId, ::Balance, - ::Rate, + ::BalanceRatio, >; pub type CurrencyIdOf = ::CurrencyId; @@ -136,9 +136,6 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -168,7 +165,11 @@ pub mod pallet { + From<[u8; 16]>; /// The fixed point number representation for higher precision. - type Rate: Parameter + Member + MaybeSerializeDeserialize + FixedPointNumber + TypeInfo; + type BalanceRatio: Parameter + + Member + + MaybeSerializeDeserialize + + FixedPointNumber + + TypeInfo; /// The origin allowed to make admin-like changes, such calling /// `set_domain_router`. @@ -180,7 +181,6 @@ pub mod pallet { type PoolInspect: PoolInspect< Self::AccountId, CurrencyIdOf, - Rate = Self::Rate, PoolId = Self::PoolId, TrancheId = Self::TrancheId, >; @@ -188,7 +188,7 @@ pub mod pallet { type TrancheTokenPrice: TrancheTokenPrice< Self::AccountId, CurrencyIdOf, - Rate = Self::Rate, + BalanceRatio = Self::BalanceRatio, PoolId = Self::PoolId, TrancheId = Self::TrancheId, >; @@ -276,33 +276,22 @@ pub mod pallet { /// beforehand as part of receiving the corresponding investment /// message. type TreasuryAccount: Get; + + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[allow(clippy::large_enum_variant)] pub enum Event { - /// A message was sent to a domain - MessageSent { - message: MessageOf, - domain: Domain, - }, - - /// The Router for a given domain was set - SetDomainRouter { - domain: Domain, - router: Router>, - }, - + /// An incoming LP message was + /// detected and is further processed IncomingMessage { - sender: T::AccountId, - message: Vec, + sender: DomainAddress, + message: MessageOf, }, } - #[pallet::storage] - pub(crate) type DomainRouter = - StorageMap<_, Blake2_128Concat, Domain, Router>>; - #[pallet::error] pub enum Error { /// Failed to map the asset to the corresponding LiquidityPools' General @@ -366,22 +355,6 @@ pub mod pallet { where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { - /// Set a Domain's router - #[pallet::weight(< T as Config >::WeightInfo::set_domain_router())] - #[pallet::call_index(0)] - pub fn set_domain_router( - origin: OriginFor, - domain: Domain, - router: Router>, - ) -> DispatchResult { - T::AdminOrigin::ensure_origin(origin.clone())?; - - >::insert(domain.clone(), router.clone()); - Self::deposit_event(Event::SetDomainRouter { domain, router }); - - Ok(()) - } - /// Add a pool to a given domain #[pallet::weight(< T as Config >::WeightInfo::add_pool())] #[pallet::call_index(2)] @@ -963,6 +936,11 @@ pub mod pallet { #[transactional] fn submit(sender: DomainAddress, msg: MessageOf) -> DispatchResult { + Self::deposit_event(Event::::IncomingMessage { + sender: sender.clone(), + message: msg.clone(), + }); + match msg { Message::Transfer { currency, diff --git a/pallets/liquidity-pools/src/weights.rs b/pallets/liquidity-pools/src/weights.rs index 8052879699..2d5b4c30ae 100644 --- a/pallets/liquidity-pools/src/weights.rs +++ b/pallets/liquidity-pools/src/weights.rs @@ -10,8 +10,7 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. - -use frame_support::weights::Weight; +use frame_support::weights::{constants::RocksDbWeight, Weight}; pub trait WeightInfo { fn add_pool() -> Weight; @@ -22,28 +21,75 @@ pub trait WeightInfo { fn set_domain_router() -> Weight; } +// NOTE: We use temporary weights here. `execute_epoch` is by far our heaviest +// extrinsic. N denotes the number of tranches. 4 is quite heavy and +// should be enough. +const N: u64 = 4; + impl WeightInfo for () { fn set_domain_router() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } fn add_pool() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } fn add_tranche() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } fn update_token_price() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } fn update_member() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } fn transfer() -> Weight { - Weight::zero() + // TODO: BENCHMARK AND USE REAL WEIGHTS + Weight::from_parts(78_019_565, 19974) + .saturating_add(Weight::from_ref_time(38_884_782).saturating_mul(N)) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(N))) + .saturating_add(RocksDbWeight::get().writes(8)) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(N))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(N)) } } diff --git a/pallets/loans/src/tests/mock.rs b/pallets/loans/src/tests/mock.rs index 59904cc2d0..90173b4346 100644 --- a/pallets/loans/src/tests/mock.rs +++ b/pallets/loans/src/tests/mock.rs @@ -196,9 +196,9 @@ impl pallet_interest_accrual::Config for Runtime { impl pallet_mock_pools::Config for Runtime { type Balance = Balance; + type BalanceRatio = Quantity; type CurrencyId = CurrencyId; type PoolId = PoolId; - type Rate = Rate; type TrancheId = TrancheId; } diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index fc5fee96df..aec43dbf3c 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -372,9 +372,27 @@ pub mod pallet { price: T::SellRatio, ) -> DispatchResult { let account_id = ensure_signed(origin)?; - Self::place_order( - account_id, asset_in, asset_out, buy_amount, price, buy_amount, + + Self::inner_place_order( + account_id, + asset_in, + asset_out, + buy_amount, + price, + buy_amount, + |order| { + let min_amount = TradingPair::::get(&asset_in, &asset_out)?; + Self::is_valid_order( + order.asset_in_id, + order.asset_out_id, + order.buy_amount, + order.max_sell_rate, + order.min_fulfillment_amount, + min_amount, + ) + }, )?; + Ok(()) } @@ -388,13 +406,29 @@ pub mod pallet { price: T::SellRatio, ) -> DispatchResult { let account_id = ensure_signed(origin)?; - let order = >::get(order_id)?; - ensure!( - account_id == order.placing_account, - Error::::Unauthorised - ); - >::update_order( - account_id, order_id, buy_amount, price, buy_amount, + Self::inner_update_order( + account_id.clone(), + order_id, + buy_amount, + price, + buy_amount, + |order| { + ensure!( + account_id == order.placing_account, + Error::::Unauthorised + ); + + let min_amount = + TradingPair::::get(&order.asset_in_id, &order.asset_out_id)?; + Self::is_valid_order( + order.asset_in_id, + order.asset_out_id, + order.buy_amount, + order.max_sell_rate, + order.min_fulfillment_amount, + min_amount, + ) + }, ) } @@ -607,28 +641,15 @@ pub mod pallet { } } - impl TokenSwaps for Pallet - where - ::Hash: PartialEq<::Hash>, - { - type Balance = T::Balance; - type CurrencyId = T::AssetCurrencyId; - type OrderDetails = Swap; - type OrderId = T::OrderIdNonce; - type SellRatio = T::SellRatio; - - /// Creates an order. - /// Verify funds available in, and reserve for both chains fee currency - /// for storage fee, and amount of outgoing currency as determined by - /// the buy amount and price. - fn place_order( - account: T::AccountId, + impl Pallet { + fn is_valid_order( currency_in: T::AssetCurrencyId, currency_out: T::AssetCurrencyId, buy_amount: T::Balance, sell_rate_limit: T::SellRatio, min_fulfillment_amount: T::Balance, - ) -> Result { + min_order_amount: T::Balance, + ) -> DispatchResult { ensure!(currency_in != currency_out, Error::::ConflictingAssetIds); ensure!( @@ -645,107 +666,31 @@ pub mod pallet { Error::::InvalidMaxPrice ); - >::try_mutate(|n| { - *n = n.ensure_add(T::OrderIdNonce::one())?; - Ok::<_, DispatchError>(()) - })?; - ensure!( buy_amount >= min_fulfillment_amount, Error::::InvalidBuyAmount ); - Self::is_valid_min_order(currency_in, currency_out, buy_amount)?; - - let max_sell_amount = - Self::convert_with_ratio(currency_in, currency_out, sell_rate_limit, buy_amount)?; - - T::TradeableAsset::hold(currency_out, &account, max_sell_amount)?; - - let order_id = >::get(); - let new_order = Order { - order_id, - placing_account: account.clone(), - asset_in_id: currency_in, - asset_out_id: currency_out, - buy_amount, - max_sell_rate: sell_rate_limit, - initial_buy_amount: buy_amount, - min_fulfillment_amount, - max_sell_amount, - }; - - >::try_mutate(currency_in, currency_out, |orders| { - orders - .try_push(order_id) - .map_err(|_| Error::::AssetPairOrdersOverflow) - })?; - - >::insert(order_id, new_order.clone()); - >::insert(&account, order_id, new_order); - Self::deposit_event(Event::OrderCreated { - creator_account: account, - sell_rate_limit, - order_id, - buy_amount, - currency_in, - currency_out, - min_fulfillment_amount, - }); - Ok(order_id) - } - - /// Cancel an existing order. - /// Unreserve currency reserved for trade as well storage fee. - fn cancel_order(order: Self::OrderId) -> DispatchResult { - let order = >::get(order)?; - let account_id = order.placing_account.clone(); - - Self::unreserve_order(&order)?; - Self::remove_order(order.order_id)?; - Self::deposit_event(Event::OrderCancelled { - account: account_id, - order_id: order.order_id, - }); + ensure!( + buy_amount >= min_order_amount, + Error::::InsufficientOrderSize + ); Ok(()) } - /// Update an existing order. - /// Update outgoing asset currency reserved to match new amount or price - /// if either have changed. - fn update_order( + fn inner_update_order( account: T::AccountId, - order_id: Self::OrderId, + order_id: T::OrderIdNonce, buy_amount: T::Balance, sell_rate_limit: T::SellRatio, min_fulfillment_amount: T::Balance, + validate: impl FnOnce(&OrderOf) -> DispatchResult, ) -> DispatchResult { - ensure!( - buy_amount != T::Balance::zero(), - Error::::InvalidBuyAmount - ); - - ensure!( - sell_rate_limit != T::SellRatio::zero(), - Error::::InvalidMaxPrice - ); - - ensure!( - min_fulfillment_amount != ::zero(), - Error::::InvalidMinimumFulfillment - ); - - ensure!( - buy_amount >= min_fulfillment_amount, - Error::::InvalidBuyAmount - ); - let max_sell_amount = >::try_mutate_exists( order_id, |maybe_order| -> Result { let mut order = maybe_order.as_mut().ok_or(Error::::OrderNotFound)?; - Self::is_valid_min_order(order.asset_in_id, order.asset_out_id, buy_amount)?; let max_sell_amount = Self::convert_with_ratio( order.asset_in_id, @@ -782,6 +727,8 @@ pub mod pallet { order.min_fulfillment_amount = min_fulfillment_amount; order.max_sell_amount = max_sell_amount; + validate(order)?; + Ok(max_sell_amount) }, )?; @@ -809,6 +756,156 @@ pub mod pallet { Ok(()) } + fn inner_place_order( + account: T::AccountId, + currency_in: T::AssetCurrencyId, + currency_out: T::AssetCurrencyId, + buy_amount: T::Balance, + sell_rate_limit: T::SellRatio, + min_fulfillment_amount: T::Balance, + validate: impl FnOnce(&OrderOf) -> DispatchResult, + ) -> Result { + >::try_mutate(|n| { + *n = n.ensure_add(T::OrderIdNonce::one())?; + Ok::<_, DispatchError>(()) + })?; + + let max_sell_amount = + Self::convert_with_ratio(currency_in, currency_out, sell_rate_limit, buy_amount)?; + + T::TradeableAsset::hold(currency_out, &account, max_sell_amount)?; + + let order_id = >::get(); + let new_order = Order { + order_id, + placing_account: account.clone(), + asset_in_id: currency_in, + asset_out_id: currency_out, + buy_amount, + max_sell_rate: sell_rate_limit, + initial_buy_amount: buy_amount, + min_fulfillment_amount, + max_sell_amount, + }; + + validate(&new_order)?; + + >::try_mutate(currency_in, currency_out, |orders| { + orders + .try_push(order_id) + .map_err(|_| Error::::AssetPairOrdersOverflow) + })?; + + >::insert(order_id, new_order.clone()); + >::insert(&account, order_id, new_order); + Self::deposit_event(Event::OrderCreated { + creator_account: account, + sell_rate_limit, + order_id, + buy_amount, + currency_in, + currency_out, + min_fulfillment_amount, + }); + + Ok(order_id) + } + } + + impl TokenSwaps for Pallet + where + ::Hash: PartialEq<::Hash>, + { + type Balance = T::Balance; + type CurrencyId = T::AssetCurrencyId; + type OrderDetails = Swap; + type OrderId = T::OrderIdNonce; + type SellRatio = T::SellRatio; + + /// Creates an order. + /// Verify funds available in, and reserve for both chains fee currency + /// for storage fee, and amount of outgoing currency as determined by + /// the buy amount and price. + fn place_order( + account: T::AccountId, + currency_in: T::AssetCurrencyId, + currency_out: T::AssetCurrencyId, + buy_amount: T::Balance, + sell_rate_limit: T::SellRatio, + min_fulfillment_amount: T::Balance, + ) -> Result { + Self::inner_place_order( + account, + currency_in, + currency_out, + buy_amount, + sell_rate_limit, + min_fulfillment_amount, + |order| { + // We only check if the trading pair exists not if the minimum amount is + // reached. + let _min_amount = TradingPair::::get(¤cy_in, ¤cy_out)?; + Self::is_valid_order( + order.asset_in_id, + order.asset_out_id, + order.buy_amount, + order.max_sell_rate, + order.min_fulfillment_amount, + T::Balance::zero(), + ) + }, + ) + } + + /// Cancel an existing order. + /// Unreserve currency reserved for trade as well storage fee. + fn cancel_order(order: Self::OrderId) -> DispatchResult { + let order = >::get(order)?; + let account_id = order.placing_account.clone(); + + Self::unreserve_order(&order)?; + Self::remove_order(order.order_id)?; + Self::deposit_event(Event::OrderCancelled { + account: account_id, + order_id: order.order_id, + }); + + Ok(()) + } + + /// Update an existing order. + /// Update outgoing asset currency reserved to match new amount or price + /// if either have changed. + fn update_order( + account: T::AccountId, + order_id: Self::OrderId, + buy_amount: T::Balance, + sell_rate_limit: T::SellRatio, + min_fulfillment_amount: T::Balance, + ) -> DispatchResult { + Self::inner_update_order( + account, + order_id, + buy_amount, + sell_rate_limit, + min_fulfillment_amount, + |order| { + // We only check if the trading pair exists not if the minimum amount is + // reached. + let _min_amount = + TradingPair::::get(&order.asset_in_id, &order.asset_out_id)?; + Self::is_valid_order( + order.asset_in_id, + order.asset_out_id, + order.buy_amount, + order.max_sell_rate, + order.min_fulfillment_amount, + T::Balance::zero(), + ) + }, + ) + } + /// Check whether an order is active. fn is_active(order: Self::OrderId) -> bool { >::contains_key(order) diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index e9c7d10356..51104b752b 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -540,16 +540,29 @@ fn ensure_nonce_updates_order_correctly() { } #[test] -fn place_order_requires_min_buy() { +fn place_order_requires_no_min_buy() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 1 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 1 * CURRENCY_AUSD_DECIMALS, + ),); + }) +} + +#[test] +fn create_order_requires_min_buy() { new_test_ext().execute_with(|| { assert_err!( - OrderBook::place_order( - ACCOUNT_0, + OrderBook::create_order( + RuntimeOrigin::signed(ACCOUNT_0), DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 1 * CURRENCY_AUSD_DECIMALS, Rate::checked_from_rational(3u32, 2u32).unwrap(), - 1 * CURRENCY_AUSD_DECIMALS, ), Error::::InsufficientOrderSize ); @@ -902,7 +915,29 @@ fn update_order_works_with_order_decrease() { } #[test] -fn update_order_requires_min_buy() { +fn update_order_requires_no_min_buy() { + new_test_ext().execute_with(|| { + assert_ok!(OrderBook::place_order( + ACCOUNT_0, + DEV_AUSD_CURRENCY_ID, + DEV_USDT_CURRENCY_ID, + 15 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_rational(3u32, 2u32).unwrap(), + 5 * CURRENCY_AUSD_DECIMALS + )); + let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; + assert_ok!(OrderBook::update_order( + ACCOUNT_0, + order_id, + 1 * CURRENCY_AUSD_DECIMALS, + Rate::checked_from_integer(1u32).unwrap(), + 1 * CURRENCY_AUSD_DECIMALS + ),); + }) +} + +#[test] +fn user_update_order_requires_min_buy() { new_test_ext().execute_with(|| { assert_ok!(OrderBook::place_order( ACCOUNT_0, @@ -914,12 +949,11 @@ fn update_order_requires_min_buy() { )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_err!( - OrderBook::update_order( - ACCOUNT_0, + OrderBook::user_update_order( + RuntimeOrigin::signed(ACCOUNT_0), order_id, 1 * CURRENCY_AUSD_DECIMALS, Rate::checked_from_integer(1u32).unwrap(), - 1 * CURRENCY_AUSD_DECIMALS ), Error::::InsufficientOrderSize ); diff --git a/pallets/pool-registry/src/lib.rs b/pallets/pool-registry/src/lib.rs index 081156cdaf..b31c9cc546 100644 --- a/pallets/pool-registry/src/lib.rs +++ b/pallets/pool-registry/src/lib.rs @@ -87,13 +87,6 @@ pub mod pallet { + MaxEncodedLen + core::fmt::Debug; - type Rate: Parameter - + Member - + MaybeSerializeDeserialize - + FixedPointNumber - + TypeInfo - + MaxEncodedLen; - /// A fixed-point number which represents an /// interest rate. type InterestRate: Member diff --git a/pallets/pool-registry/src/mock.rs b/pallets/pool-registry/src/mock.rs index 81f409664a..2347dd0878 100644 --- a/pallets/pool-registry/src/mock.rs +++ b/pallets/pool-registry/src/mock.rs @@ -17,7 +17,7 @@ use cfg_traits::{ investments::OrderManager, PoolMutate, PoolUpdateGuard, PreConditions, UpdateState, }; use cfg_types::{ - fixed_point::Rate, + fixed_point::{Quantity, Rate}, permissions::{PermissionScope, Role}, tokens::{CurrencyId, CustomMetadata, TrancheCurrency}, }; @@ -140,6 +140,7 @@ impl cfg_test_utils::mocks::nav::Config for Test { impl pallet_pool_system::Config for Test { type AssetRegistry = RegistryMock; type Balance = Balance; + type BalanceRatio = Quantity; type ChallengeTime = ChallengeTime; type Currency = Balances; type CurrencyId = CurrencyId; @@ -211,7 +212,6 @@ impl< ::MaxTokenSymbolLength, ::MaxTranches, >; - type Rate = ::Rate; type TrancheInput = TrancheInput< ::Rate, ::MaxTokenNameLength, @@ -271,7 +271,6 @@ impl Config for Test { type Permission = PermissionsMock; type PoolCreateOrigin = EnsureSigned; type PoolId = u64; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; @@ -319,7 +318,7 @@ parameter_types! { impl pallet_investments::Config for Test { type Accountant = PoolSystem; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = NoopCollectHook; type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = TrancheCurrency; diff --git a/pallets/pool-system/src/impls.rs b/pallets/pool-system/src/impls.rs index 0c16a88a86..413cc37d9b 100644 --- a/pallets/pool-system/src/impls.rs +++ b/pallets/pool-system/src/impls.rs @@ -31,7 +31,6 @@ use crate::{ impl PoolInspect for Pallet { type Moment = Moment; type PoolId = T::PoolId; - type Rate = T::Rate; type TrancheId = T::TrancheId; fn pool_exists(pool_id: Self::PoolId) -> bool { @@ -54,15 +53,15 @@ impl PoolInspect for Pallet { } impl TrancheTokenPrice for Pallet { + type BalanceRatio = T::BalanceRatio; type Moment = Moment; type PoolId = T::PoolId; - type Rate = T::Rate; type TrancheId = T::TrancheId; fn get( pool_id: Self::PoolId, tranche_id: Self::TrancheId, - ) -> Option> { + ) -> Option> { let now = Self::now(); let mut pool = Pool::::get(pool_id)?; @@ -78,7 +77,7 @@ impl TrancheTokenPrice for Pallet { .ok()?; let prices = pool .tranches - .calculate_prices::(total_assets, now) + .calculate_prices::(total_assets, now) .ok()?; let base = pool @@ -106,7 +105,6 @@ impl PoolMutate for Pallet { type MaxTokenSymbolLength = T::MaxTokenSymbolLength; type MaxTranches = T::MaxTranches; type PoolChanges = PoolChangesOf; - type Rate = T::Rate; type TrancheInput = TrancheInput; fn create( diff --git a/pallets/pool-system/src/lib.rs b/pallets/pool-system/src/lib.rs index 21baca064f..fcbf075760 100644 --- a/pallets/pool-system/src/lib.rs +++ b/pallets/pool-system/src/lib.rs @@ -78,7 +78,7 @@ pub mod weights; #[allow(dead_code)] pub type EpochExecutionTrancheOf = EpochExecutionTranche< ::Balance, - ::Rate, + ::BalanceRatio, ::TrancheWeight, ::TrancheCurrency, >; @@ -87,7 +87,7 @@ pub type EpochExecutionTrancheOf = EpochExecutionTranche< /// Type alias for EpochExecutionTranches pub type EpochExecutionTranchesOf = EpochExecutionTranches< ::Balance, - ::Rate, + ::BalanceRatio, ::TrancheWeight, ::TrancheCurrency, ::MaxTranches, @@ -129,7 +129,7 @@ pub type PoolDetailsOf = PoolDetails< /// Type alias for `struct EpochExecutionInfo` type EpochExecutionInfoOf = EpochExecutionInfo< ::Balance, - ::Rate, + ::BalanceRatio, ::EpochId, ::TrancheWeight, ::BlockNumber, @@ -215,6 +215,15 @@ pub mod pallet { + Convert + From; + /// A fixed-point number that represent a price with decimals + type BalanceRatio: Member + + Parameter + + Default + + Copy + + TypeInfo + + FixedPointNumber + + MaxEncodedLen; + /// A fixed-point number which represents a Self::Balance /// in terms of this fixed-point representation. type Rate: Member @@ -304,7 +313,7 @@ pub mod pallet { Error = DispatchError, InvestmentId = Self::TrancheCurrency, Orders = TotalOrder, - Fulfillment = FulfillmentWithPrice, + Fulfillment = FulfillmentWithPrice, >; type Time: UnixTime; @@ -357,8 +366,11 @@ pub mod pallet { type WeightInfo: WeightInfo; } + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::storage] @@ -384,10 +396,6 @@ pub mod pallet { #[pallet::getter(fn pool_deposits)] pub type PoolDeposit = StorageMap<_, Blake2_128Concat, T::PoolId, PoolDepositOf>; - #[pallet::storage] - #[pallet::getter(fn storage_version)] - pub type StorageVersion = StorageValue<_, Release, ValueQuery>; - #[pallet::storage] pub type NotedChange = StorageDoubleMap< _, @@ -607,7 +615,7 @@ pub mod pallet { let epoch_tranche_prices = pool .tranches - .calculate_prices::(total_assets, now)?; + .calculate_prices::(total_assets, now)?; // If closing the epoch would wipe out a tranche, the close is invalid. // TODO: This should instead put the pool into an error state @@ -878,7 +886,7 @@ pub mod pallet { fn summarize_orders( tranches: &TranchesOf, - prices: &[T::Rate], + prices: &[T::BalanceRatio], ) -> Result, DispatchError> { let mut acc_invest_orders = T::Balance::zero(); let mut acc_redeem_orders = T::Balance::zero(); diff --git a/pallets/pool-system/src/mock.rs b/pallets/pool-system/src/mock.rs index 6a13a50fc3..6e90c8f7f9 100644 --- a/pallets/pool-system/src/mock.rs +++ b/pallets/pool-system/src/mock.rs @@ -15,7 +15,7 @@ use cfg_traits::{ investments::{OrderManager, TrancheCurrency as TrancheCurrencyT}, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, }; -pub use cfg_types::fixed_point::Rate; +pub use cfg_types::fixed_point::{Quantity, Rate}; use cfg_types::{ permissions::{PermissionRoles, PermissionScope, PoolRole, Role, UNION}, time::TimeProvider, @@ -266,7 +266,7 @@ parameter_types! { impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = NoopCollectHook; type CollectedRedemptionHook = NoopCollectHook; type InvestmentId = TrancheCurrency; @@ -319,6 +319,7 @@ parameter_types! { impl Config for Runtime { type AssetRegistry = RegistryMock; type Balance = Balance; + type BalanceRatio = Quantity; type ChallengeTime = ChallengeTime; type Currency = Balances; type CurrencyId = CurrencyId; diff --git a/pallets/pool-system/src/tests/mod.rs b/pallets/pool-system/src/tests/mod.rs index 29ebdd03e3..f9f6bf3941 100644 --- a/pallets/pool-system/src/tests/mod.rs +++ b/pallets/pool-system/src/tests/mod.rs @@ -153,7 +153,7 @@ fn core_constraints_currency_available_cant_cover_redemptions() { .zip(vec![80, 20, 5, 5]) // no IntoIterator for arrays, so we use a vec here. Meh. .map(|(_tranche, value)| EpochExecutionTranche { supply: value, - price: One::one(), + price: Quantity::one(), redeem: 10, ..Default::default() }) @@ -502,7 +502,7 @@ fn pool_constraints_pass() { assert_ok!(PoolSystem::inspect_solution(pool, &epoch, &full_solution)); assert_eq!( - calculate_risk_buffers::(&vec![3, 1], &vec![One::one(), One::one()]) + calculate_risk_buffers::(&vec![3, 1], &vec![One::one(), One::one()]) .unwrap(), vec![Perquintill::zero(), Perquintill::from_float(0.75),] ); @@ -577,7 +577,7 @@ fn epoch() { >>::get(0, SeniorTrancheId::get()) .unwrap() .price, - Rate::one() + Quantity::one() ); assert_err!( @@ -725,14 +725,14 @@ fn epoch() { 0 ); assert_eq!(pool.reserve.available, pool.reserve.total); - assert_eq!(pool.reserve.total, 758968368969420653370); + assert_eq!(pool.reserve.total, 758968368969420653250); assert_eq!( pool.tranches.residual_top_slice()[SENIOR_TRANCHE_INDEX as usize].reserve, - 251031631030579346631 + 251031631030579346511 ); assert_eq!( pool.reserve.total + senior_price.saturating_mul_int(250 * CURRENCY), - 1010 * CURRENCY + 1 // TODO: Fix rounding issue with FixedPointNumberExtension + 1009999999999999999750 // TODO: Fix rounding issue with FixedPointNumberExtension ); assert_eq!( @@ -742,7 +742,7 @@ fn epoch() { >>::get(0, SeniorTrancheId::get()) .unwrap() .price, - Rate::from_inner(1004126524122317386524000000) + Quantity::from_inner(1004126524122317386) ); }); } diff --git a/pallets/pool-system/src/tranches.rs b/pallets/pool-system/src/tranches.rs index 232ff06a31..d06b844f9e 100644 --- a/pallets/pool-system/src/tranches.rs +++ b/pallets/pool-system/src/tranches.rs @@ -15,7 +15,10 @@ use cfg_primitives::Moment; use cfg_primitives::{Balance, PoolId, TrancheId, TrancheWeight}; use cfg_traits::investments::TrancheCurrency as TrancheCurrencyT; #[cfg(test)] -use cfg_types::{fixed_point::Rate, tokens::TrancheCurrency}; +use cfg_types::{ + fixed_point::{Quantity, Rate}, + tokens::TrancheCurrency, +}; use cfg_types::{ pools::TrancheMetadata, tokens::{CrossChainTransferability, CustomMetadata}, @@ -1048,12 +1051,12 @@ pub struct EpochExecutionTranche } #[cfg(test)] -impl Default for EpochExecutionTranche { +impl Default for EpochExecutionTranche { fn default() -> Self { Self { currency: TrancheCurrency::generate(0, [0u8; 16]), supply: 0, - price: Rate::one(), + price: Quantity::one(), invest: 0, redeem: 0, min_risk_buffer: Default::default(), @@ -1524,14 +1527,14 @@ fn finalize_combine( pub mod test { use cfg_primitives::{Balance, PoolId, TrancheId, TrancheWeight}; use cfg_types::{ - fixed_point::{FixedPointNumberExtension, Rate}, + fixed_point::{FixedPointNumberExtension, Quantity, Rate}, tokens::TrancheCurrency, }; use super::*; use crate::mock::MaxTranches; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type TTrancheType = TrancheType; type TTranche = Tranche; type TTranches = @@ -3861,7 +3864,7 @@ pub mod test { let tranches = default_epoch_tranches(); assert_eq!( - vec![Rate::one(), Rate::one(), Rate::one()], + vec![Quantity::one(), Quantity::one(), Quantity::one()], tranches.prices() ) } @@ -4099,7 +4102,7 @@ pub mod test { #[test] fn epoch_execution_tranches_prices() { let epoch_execution_tranches = default_epoch_tranches(); - let r = Rate::one(); + let r = Quantity::one(); assert_eq!(epoch_execution_tranches.prices(), vec![r, r, r]) } } diff --git a/pallets/transfer-allowlist/src/lib.rs b/pallets/transfer-allowlist/src/lib.rs index d807a6d9dc..6e3b34bef1 100644 --- a/pallets/transfer-allowlist/src/lib.rs +++ b/pallets/transfer-allowlist/src/lib.rs @@ -34,7 +34,7 @@ pub mod weights; pub use cfg_traits::TransferAllowance; pub use pallet::*; -pub use weights::Weights; +pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { @@ -116,7 +116,7 @@ pub mod pallet { + MaxEncodedLen; /// Type for pallet weights - type Weights: Weights; + type WeightInfo: WeightInfo; } // @@ -324,7 +324,7 @@ pub mod pallet { /// Running this for an existing allowance generates a new allowance /// based on the current delay, or lack thereof #[pallet::call_index(0)] - #[pallet::weight(T::Weights::add_transfer_allowance_no_existing_metadata().max(T::Weights::add_transfer_allowance_existing_metadata()))] + #[pallet::weight(T::WeightInfo::add_transfer_allowance_no_existing_metadata().max(T::WeightInfo::add_transfer_allowance_existing_metadata()))] pub fn add_transfer_allowance( origin: OriginFor, currency_id: T::CurrencyId, @@ -377,7 +377,7 @@ pub mod pallet { /// - either the current block + delay if a delay is set /// - or the current block if no delay is set #[pallet::call_index(1)] - #[pallet::weight(T::Weights::remove_transfer_allowance_missing_allowance().max(T::Weights::remove_transfer_allowance_delay_present()))] + #[pallet::weight(T::WeightInfo::remove_transfer_allowance_missing_allowance().max(T::WeightInfo::remove_transfer_allowance_delay_present()))] pub fn remove_transfer_allowance( origin: OriginFor, currency_id: T::CurrencyId, @@ -423,7 +423,7 @@ pub mod pallet { /// receiving location Decrements or removes the sending /// account/currency count. #[pallet::call_index(2)] - #[pallet::weight(T::Weights::purge_transfer_allowance_no_remaining_metadata().max(T::Weights::purge_allowance_delay_remaining_metadata()))] + #[pallet::weight(T::WeightInfo::purge_transfer_allowance_no_remaining_metadata().max(T::WeightInfo::purge_allowance_delay_remaining_metadata()))] pub fn purge_transfer_allowance( origin: OriginFor, currency_id: T::CurrencyId, @@ -457,7 +457,7 @@ pub mod pallet { } #[pallet::call_index(3)] - #[pallet::weight(T::Weights::add_allowance_delay_existing_metadata().max(T::Weights::add_allowance_delay_no_existing_metadata()))] + #[pallet::weight(T::WeightInfo::add_allowance_delay_existing_metadata().max(T::WeightInfo::add_allowance_delay_no_existing_metadata()))] /// Adds an account/currency delay /// Calling on an account/currency with an existing delay will fail. /// To update a delay the delay has to be set to future modifiable. @@ -502,7 +502,7 @@ pub mod pallet { } #[pallet::call_index(4)] - #[pallet::weight(T::Weights::update_allowance_delay())] + #[pallet::weight(T::WeightInfo::update_allowance_delay())] /// Updates an allowance delay, only callable if the delay has been set /// to allow future modifications and the delay modifiable_at block has /// been passed. @@ -550,7 +550,7 @@ pub mod pallet { } #[pallet::call_index(5)] - #[pallet::weight(T::Weights::toggle_allowance_delay_once_future_modifiable())] + #[pallet::weight(T::WeightInfo::toggle_allowance_delay_once_future_modifiable())] /// This allows the delay value to be modified after the current delay /// has passed since the current block Or sets the delay value to be not /// modifiable iff modifiable at has already passed @@ -602,7 +602,7 @@ pub mod pallet { } #[pallet::call_index(6)] - #[pallet::weight(T::Weights::purge_allowance_delay_remaining_metadata().max(T::Weights::purge_allowance_delay_no_remaining_metadata()))] + #[pallet::weight(T::WeightInfo::purge_allowance_delay_remaining_metadata().max(T::WeightInfo::purge_allowance_delay_no_remaining_metadata()))] /// Removes an existing sending account/currency delay pub fn purge_allowance_delay( origin: OriginFor, diff --git a/pallets/transfer-allowlist/src/mock.rs b/pallets/transfer-allowlist/src/mock.rs index 91a96c0d54..aefd08b190 100644 --- a/pallets/transfer-allowlist/src/mock.rs +++ b/pallets/transfer-allowlist/src/mock.rs @@ -168,7 +168,7 @@ impl transfer_allowlist::Config for Runtime { type Location = Location; type ReserveCurrency = Balances; type RuntimeEvent = RuntimeEvent; - type Weights = (); + type WeightInfo = (); } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/transfer-allowlist/src/weights.rs b/pallets/transfer-allowlist/src/weights.rs index bde4dd1656..5d3ff74e01 100644 --- a/pallets/transfer-allowlist/src/weights.rs +++ b/pallets/transfer-allowlist/src/weights.rs @@ -10,9 +10,16 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -pub use frame_support::weights::Weight; +#![allow(unused_parens)] +#![allow(unused_imports)] -pub trait Weights { +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +pub trait WeightInfo { fn add_transfer_allowance_no_existing_metadata() -> Weight; fn add_transfer_allowance_existing_metadata() -> Weight; fn add_allowance_delay_no_existing_metadata() -> Weight; @@ -28,56 +35,247 @@ pub trait Weights { fn purge_transfer_allowance_remaining_metadata() -> Weight; } -impl Weights for () { +/// Weights for pallet_transfer_allowlist using the Substrate node and +/// recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) fn add_transfer_allowance_no_existing_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 40_000 nanoseconds. + Weight::from_ref_time(41_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) fn add_transfer_allowance_existing_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn add_allowance_delay_no_existing_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 18_000 nanoseconds. + Weight::from_ref_time(18_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn add_allowance_delay_existing_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 19_000 nanoseconds. + Weight::from_ref_time(20_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn toggle_allowance_delay_once_future_modifiable() -> Weight { - Weight::zero() + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(20_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn update_allowance_delay() -> Weight { - Weight::zero() + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn purge_allowance_delay_no_remaining_metadata() -> Weight { + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn purge_allowance_delay_remaining_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + fn remove_transfer_allowance_missing_allowance() -> Weight { + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + fn remove_transfer_allowance_delay_present() -> Weight { + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + fn remove_transfer_allowance_no_delay() -> Weight { + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn purge_transfer_allowance_no_remaining_metadata() -> Weight { + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn purge_transfer_allowance_remaining_metadata() -> Weight { + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(44_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} + +impl WeightInfo for () { + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn add_transfer_allowance_no_existing_metadata() -> Weight { + // Minimum execution time: 40_000 nanoseconds. + Weight::from_ref_time(41_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + fn add_transfer_allowance_existing_metadata() -> Weight { + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn add_allowance_delay_no_existing_metadata() -> Weight { + // Minimum execution time: 18_000 nanoseconds. + Weight::from_ref_time(18_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn add_allowance_delay_existing_metadata() -> Weight { + // Minimum execution time: 19_000 nanoseconds. + Weight::from_ref_time(20_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn toggle_allowance_delay_once_future_modifiable() -> Weight { + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(20_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn update_allowance_delay() -> Weight { + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn purge_allowance_delay_no_remaining_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) + fn purge_allowance_delay_remaining_metadata() -> Weight { + // Minimum execution time: 20_000 nanoseconds. + Weight::from_ref_time(21_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) fn remove_transfer_allowance_missing_allowance() -> Weight { - Weight::zero() + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) fn remove_transfer_allowance_delay_present() -> Weight { - Weight::zero() + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) fn remove_transfer_allowance_no_delay() -> Weight { - Weight::zero() + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn purge_transfer_allowance_no_remaining_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(43_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + // Storage: Fees FeeBalances (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:1) fn purge_transfer_allowance_remaining_metadata() -> Weight { - Weight::zero() + // Minimum execution time: 43_000 nanoseconds. + Weight::from_ref_time(44_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } } diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index c001f00c8d..f212889ca4 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "altair-runtime" -version = "0.10.30" +version = "0.10.32" authors = ["Centrifuge "] edition = "2021" build = "build.rs" diff --git a/runtime/altair/src/evm.rs b/runtime/altair/src/evm.rs index 347e58c406..f89fc02221 100644 --- a/runtime/altair/src/evm.rs +++ b/runtime/altair/src/evm.rs @@ -10,9 +10,8 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{AccountId, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; +use cfg_primitives::{EnsureRootOr, HalfOfCouncil, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; use frame_support::{parameter_types, traits::FindAuthor, weights::Weight, ConsensusEngineId}; -use frame_system::EnsureRoot; use pallet_evm::{EnsureAddressRoot, EnsureAddressTruncated}; use runtime_common::{ account_conversion::AccountConverter, @@ -22,7 +21,7 @@ use sp_core::{crypto::ByteArray, H160, U256}; use sp_runtime::Permill; use sp_std::marker::PhantomData; -use crate::{Aura, Runtime, RuntimeEvent}; +use crate::{Aura, LocationToAccountId, Runtime, RuntimeEvent}; /// To create valid Ethereum-compatible blocks, we need a 20-byte /// "author" for the block. Since that author is purely informational, @@ -48,7 +47,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { - type AddressMapping = AccountConverter; + type AddressMapping = AccountConverter; type BlockGasLimit = BlockGasLimit; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressRoot; @@ -86,11 +85,10 @@ impl pallet_ethereum::Config for Runtime { type StateRoot = pallet_ethereum::IntermediateStateRoot; } -impl pallet_ethereum_transaction::Config for Runtime { - type RuntimeEvent = RuntimeEvent; -} +impl pallet_ethereum_transaction::Config for Runtime {} impl axelar_gateway_precompile::Config for Runtime { - type AdminOrigin = EnsureRoot; + type AdminOrigin = EnsureRootOr; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index b0c7220b68..97ba04928b 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -19,11 +19,11 @@ // Allow things like `1 * CFG` #![allow(clippy::identity_op)] -use ::xcm::latest::{MultiAsset, MultiLocation}; +use ::xcm::v3::{MultiAsset, MultiLocation}; pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as _}, - Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, TryConvert, }; pub use cfg_types::tokens::CurrencyId; use cfg_types::{ @@ -73,8 +73,11 @@ pub use pallet_timestamp::Call as TimestampCall; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, RuntimeDispatchInfo}; use polkadot_runtime_common::{prod_or_fast, BlockHashCount, SlowAdjustingFeeUpdate}; -use runtime_common::fees::{DealWithFees, WeightToFee}; pub use runtime_common::*; +use runtime_common::{ + fees::{DealWithFees, WeightToFee}, + gateway::GatewayAccountProvider, +}; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H160, H256, U256}; @@ -124,7 +127,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("altair"), impl_name: create_runtime_str!("altair"), authoring_version: 1, - spec_version: 1030, + spec_version: 1032, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1418,16 +1421,16 @@ impl pallet_liquidity_pools::Config for Runtime { type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; + type BalanceRatio = Quantity; type CurrencyId = CurrencyId; - type DomainAccountToAccountId = AccountConverter; - type DomainAddressToAccountId = AccountConverter; + type DomainAccountToAccountId = AccountConverter; + type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; type OutboundQueue = LiquidityPoolsGateway; type Permission = Permissions; type PoolId = PoolId; type PoolInspect = PoolSystem; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type Time = Timestamp; type Tokens = Tokens; @@ -1440,17 +1443,48 @@ impl pallet_liquidity_pools::Config for Runtime { parameter_types! { pub const MaxIncomingMessageSize: u32 = 1024; + pub Sender: AccountId = GatewayAccountProvider::::get_gateway_account(); +} + +/// A +pub struct StumbInboundQueue; +impl InboundQueue for StumbInboundQueue { + type Message = pallet_liquidity_pools::Message; + type Sender = DomainAddress; + + fn submit(sender: Self::Sender, message: Self::Message) -> DispatchResult { + let event = { + let event = + pallet_liquidity_pools::Event::::IncomingMessage { sender, message }; + + // Mirror deposit_event logic here as it is private + let event = <::RuntimeEvent as From< + pallet_liquidity_pools::Event, + >>::from(event); + + <::RuntimeEvent as Into< + ::RuntimeEvent, + >>::into(event) + }; + + // Triggering only the event for error resolution + System::deposit_event(event); + + Ok(()) + } } impl pallet_liquidity_pools_gateway::Config for Runtime { - type AdminOrigin = EnsureRoot; - type InboundQueue = LiquidityPools; + type AdminOrigin = EnsureRootOr; + type InboundQueue = StumbInboundQueue; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; - type Message = pallet_liquidity_pools::Message; + type Message = pallet_liquidity_pools::Message; + type OriginRecovery = LiquidityPoolsAxelarGateway; type Router = liquidity_pools_gateway_routers::DomainRouter; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; + type Sender = Sender; type WeightInfo = (); } @@ -1539,6 +1573,7 @@ parameter_types! { impl pallet_pool_system::Config for Runtime { type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; + type BalanceRatio = Quantity; type ChallengeTime = ChallengeTime; type Currency = Balances; type CurrencyId = CurrencyId; @@ -1593,7 +1628,6 @@ impl pallet_pool_registry::Config for Runtime { type Permission = Permissions; type PoolCreateOrigin = PoolCreateOrigin; type PoolId = PoolId; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; @@ -1685,7 +1719,7 @@ parameter_types! { impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = pallet_foreign_investments::hooks::CollectedInvestmentHook; type CollectedRedemptionHook = @@ -1852,7 +1886,7 @@ construct_runtime!( // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 121, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Config, Event, Origin} = 121, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 122, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 123, XTokens: orml_xtokens::{Pallet, Storage, Call, Event} = 124, @@ -1870,7 +1904,7 @@ construct_runtime!( EVMChainId: pallet_evm_chain_id::{Pallet, Config, Storage} = 161, BaseFee: pallet_base_fee::{Pallet, Call, Config, Storage, Event} = 162, Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 163, - EthereumTransaction: pallet_ethereum_transaction::{Pallet, Storage, Event} = 164, + EthereumTransaction: pallet_ethereum_transaction::{Pallet, Storage} = 164, LiquidityPoolsAxelarGateway: axelar_gateway_precompile::{Pallet, Call, Storage, Event} = 165, // migration pallet @@ -1911,7 +1945,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - migrations::UpgradeAltair1030, + migrations::UpgradeAltair1032, >; impl fp_self_contained::SelfContainedCall for RuntimeCall { @@ -2025,7 +2059,8 @@ mod __runtime_api_use { #[cfg(not(feature = "disable-runtime-api"))] use __runtime_api_use::*; -use cfg_types::domain_address::Domain; +use cfg_traits::liquidity_pools::InboundQueue; +use cfg_types::domain_address::{Domain, DomainAddress}; use runtime_common::{account_conversion::AccountConverter, xcm::AccountIdToMultiLocation}; #[cfg(not(feature = "disable-runtime-api"))] @@ -2238,6 +2273,11 @@ impl_runtime_apis! { } } + impl runtime_common::apis::AccountConversionApi for Runtime { + fn conversion_of(location: MultiLocation) -> Option { + AccountConverter::::try_convert(location).ok() + } + } // Frontier APIs impl fp_rpc::EthereumRuntimeRPCApi for Runtime { diff --git a/runtime/altair/src/migrations.rs b/runtime/altair/src/migrations.rs index 4c0ce3b911..1aad7da33b 100644 --- a/runtime/altair/src/migrations.rs +++ b/runtime/altair/src/migrations.rs @@ -9,197 +9,218 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::Balance; -use cfg_types::tokens::CurrencyId; -use codec::{Decode, Encode}; -#[cfg(feature = "try-runtime")] -use frame_support::ensure; use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; -use sp_std::vec::Vec; -use crate::{RocksDbWeight, Runtime}; - -/// The migration set for Altair 1030 @ Kusama. It includes all the migrations +/// The migration set for Altair 1031 @ Kusama. It includes all the migrations /// that have to be applied on that chain, which includes migrations that have /// already been executed on Algol (1028 & 1029). #[cfg(not(feature = "testnet-runtime"))] -pub type UpgradeAltair1030 = ( - asset_registry::CrossChainTransferabilityMigration, - orml_tokens_migration::CurrencyIdRefactorMigration, - pool_system::MigrateAUSDPools, - runtime_common::migrations::nuke::Migration, - runtime_common::migrations::nuke::Migration, +pub type UpgradeAltair1032 = ( + // FIXME: This migration fails to decode 4 entries against Altair + // orml_tokens_migration::CurrencyIdRefactorMigration, + // At minimum, bumps storage version from 1 to 2 + runtime_common::migrations::nuke::Migration, + // At minimum, bumps storage version from 0 to 3 + runtime_common::migrations::nuke::Migration, + // At minimum, bumps storage version from 0 to 1 + runtime_common::migrations::nuke::Migration, + // At minimum, bumps storage version from 0 to 1 + runtime_common::migrations::nuke::Migration, + // Funds pallet_rewards::Instance2 account with existential deposit pallet_rewards::migrations::new_instance::FundExistentialDeposit< crate::Runtime, pallet_rewards::Instance2, crate::NativeToken, crate::ExistentialDeposit, >, + // Removes metadata containing xcm_v1 locations of registered assets and sets to hardcoded ones + // containing xcm_v3 locations + runtime_common::migrations::asset_registry_xcmv3::Migration< + crate::Runtime, + asset_registry::AltairAssets, + 5, + 5, + 2, + 9, + >, + // Low weight, mainly bumps storage version to latest (v1 to v2) + crate::DmpQueue, + // Low weight, mainly bumps storage version to latest (v2 to v3) + crate::XcmpQueue, + // Low weight, bumps uninitialized storage version from v0 to v1 + pallet_xcm::migration::v1::MigrateToV1, + // Sets currently unset safe XCM version to v2 + xcm_v2_to_v3::SetSafeXcmVersion, ); /// The Upgrade set for Algol - it excludes the migrations already executed in -/// the side releases that only landed on Algol (1028 & 1029) but not yet on +/// the side releases that only landed on Algol (1028 to 1031) but not yet on /// Altair. #[cfg(feature = "testnet-runtime")] -pub type UpgradeAltair1030 = ( - runtime_common::migrations::nuke::Migration, - runtime_common::migrations::nuke::Migration, - pallet_rewards::migrations::new_instance::FundExistentialDeposit< - crate::Runtime, - pallet_rewards::Instance2, - crate::NativeToken, - crate::ExistentialDeposit, - >, -); - -const DEPRECATED_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::AUSD; -const NEW_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); +pub type UpgradeAltair1032 = (); mod asset_registry { - use cfg_types::{tokens as v1, tokens::CustomMetadata}; - use frame_support::{pallet_prelude::OptionQuery, storage_alias, Twox64Concat}; - use orml_traits::asset_registry::AssetMetadata; - - use super::*; - use crate::VERSION; - - /// Migrate all the registered asset's metadata to the new version of - /// `CustomMetadata` which contains a `CrossChainTransferability` property. - /// At this point in time, the `transferability` of Tranche tokens should be - /// set to `CrossChainTransferability::Xcm` and for all other tokens to - /// `CrossChainTransferability::Xcm`, with the exception of - /// `Currency::Staking` tokens which are not registered in the first place. - pub struct CrossChainTransferabilityMigration; - - // The old orml_asset_registry Metadata storage using v0::CustomMetadata - #[storage_alias] - type Metadata = StorageMap< - orml_asset_registry::Pallet, - Twox64Concat, - CurrencyId, - AssetMetadata, - OptionQuery, - >; - - impl OnRuntimeUpgrade for CrossChainTransferabilityMigration { - fn on_runtime_upgrade() -> Weight { - if VERSION.spec_version > 1030 { - return Weight::zero(); - } - - orml_asset_registry::Metadata::::translate( - |asset_id: CurrencyId, old_metadata: AssetMetadata| { - match asset_id { - CurrencyId::Staking(_) => None, - CurrencyId::Tranche(_, _) => Some(to_metadata_v1( - old_metadata, - v1::CrossChainTransferability::LiquidityPools, - )), - _ => Some(to_metadata_v1( - old_metadata.clone(), - v1::CrossChainTransferability::Xcm(old_metadata.additional.xcm), - )), - } - }, - ); - - let n = orml_asset_registry::Metadata::::iter().count() as u64; - ::DbWeight::get().reads_writes(n, n) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let old_state: Vec<(CurrencyId, AssetMetadata)> = - Metadata::::iter().collect::>(); - - Ok(old_state.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(old_state_encoded: Vec) -> Result<(), &'static str> { - let old_state = sp_std::vec::Vec::<( - CurrencyId, - AssetMetadata, - )>::decode(&mut old_state_encoded.as_ref()) - .map_err(|_| "Error decoding pre-upgrade state")?; - - for (asset_id, old_metadata) in old_state { - let new_metadata = crate::OrmlAssetRegistry::metadata(asset_id) - .ok_or_else(|| "New state lost the metadata of an asset")?; - - match asset_id { - CurrencyId::Tranche(_, _) => ensure!(new_metadata == to_metadata_v1( - old_metadata, - v1::CrossChainTransferability::LiquidityPools, - ), "The metadata of a tranche token wasn't just updated by setting `transferability` to `LiquidityPools `"), - _ => ensure!(new_metadata == to_metadata_v1( - old_metadata.clone(), - v1::CrossChainTransferability::Xcm(old_metadata.additional.xcm), - ), "The metadata of a NON tranche token wasn't just updated by setting `transferability` to `Xcm`"), - } + use cfg_primitives::Balance; + use cfg_types::{ + tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, + xcm::XcmMetadata, + }; + use sp_std::{vec, vec::Vec}; + use xcm::{v3::prelude::*, VersionedMultiLocation}; + + pub const ALTAIR_ASSET_LOC_COUNT: u32 = 5; + pub const ALTAIR_ASSET_METADATA_COUNT: u32 = 5; + + pub struct AltairAssets; + impl runtime_common::migrations::asset_registry_xcmv3::AssetsToMigrate for AltairAssets { + fn get_assets_to_migrate( + loc_count: u32, + meta_count: u32, + ) -> Vec<( + CurrencyId, + orml_asset_registry::AssetMetadata, + )> { + match (loc_count, meta_count) { + (loc, meta) + if (loc, meta) == (ALTAIR_ASSET_LOC_COUNT, ALTAIR_ASSET_METADATA_COUNT) => + { + Self::get_altair_assets() + } + _ => vec![], } - - Ok(()) - } - } - - mod v0 { - use cfg_types::xcm::XcmMetadata; - use codec::{Decode, Encode, MaxEncodedLen}; - use scale_info::TypeInfo; - #[cfg(feature = "std")] - use serde::{Deserialize, Serialize}; - - // The `CustomMetadata` type as it was prior to adding the `transferability` - // field and prior to removing the `xcm` field. - #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive( - Clone, - Copy, - Default, - PartialOrd, - Ord, - PartialEq, - Eq, - Debug, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - )] - pub struct CustomMetadata { - pub xcm: XcmMetadata, - pub mintable: bool, - pub permissioned: bool, - pub pool_currency: bool, } } - fn to_metadata_v1( - old: AssetMetadata, - transferability: v1::CrossChainTransferability, - ) -> AssetMetadata { - AssetMetadata { - decimals: old.decimals, - name: old.name, - symbol: old.symbol, - existential_deposit: old.existential_deposit, - location: old.location, - additional: CustomMetadata { - mintable: old.additional.mintable, - permissioned: old.additional.permissioned, - pool_currency: old.additional.pool_currency, - transferability, - }, + impl AltairAssets { + pub fn get_altair_assets() -> Vec<( + CurrencyId, + orml_asset_registry::AssetMetadata, + )> { + let mut gk = [0u8; 32]; + gk[1] = 1; + + // 0x0081 + let mut gk_acala = [0u8; 32]; + gk_acala[..2].copy_from_slice(&[0, 129]); + + // Skipping AUSD since it seems that should be registered differently, lets do + // it manually later on + vec![ + ( + CurrencyId::Native, + orml_asset_registry::AssetMetadata { + decimals: 18, + name: b"Altair".to_vec(), + symbol: b"AIR".to_vec(), + existential_deposit: 1_000_000_000_000u128, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + Junctions::X2( + Parachain(crate::ParachainInfo::parachain_id().into()), + GeneralKey { + length: 2, + data: gk, + }, + ), + ))), + additional: CustomMetadata { + mintable: false, + permissioned: false, + pool_currency: false, + transferability: CrossChainTransferability::Xcm(XcmMetadata { + fee_per_second: None, + }), + }, + }, + ), + ( + CurrencyId::ForeignAsset(1), + orml_asset_registry::AssetMetadata { + decimals: 6, + name: b"Tether USDT".to_vec(), + symbol: b"USDT".to_vec(), + existential_deposit: 10_000u128, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + Junctions::X3(Parachain(1000), PalletInstance(50), GeneralIndex(1984)), + ))), + additional: CustomMetadata { + mintable: false, + permissioned: false, + pool_currency: true, + transferability: CrossChainTransferability::Xcm(XcmMetadata { + fee_per_second: None, + }), + }, + }, + ), + ( + CurrencyId::ForeignAsset(2), + orml_asset_registry::AssetMetadata { + decimals: 12, + name: b"Acala Dollar".to_vec(), + symbol: b"aUSD".to_vec(), + existential_deposit: 10_000_000_000u128, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + Junctions::X2( + Parachain(2000), + GeneralKey { + length: 2, + data: gk_acala, + }, + ), + ))), + additional: CustomMetadata { + mintable: false, + permissioned: false, + pool_currency: true, + transferability: CrossChainTransferability::Xcm(XcmMetadata { + fee_per_second: None, + }), + }, + }, + ), + ( + CurrencyId::ForeignAsset(3), + orml_asset_registry::AssetMetadata { + decimals: 12, + name: b"Kusama".to_vec(), + symbol: b"KSM".to_vec(), + existential_deposit: 10_000_000_000u128, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + Junctions::Here, + ))), + additional: CustomMetadata { + mintable: false, + permissioned: false, + pool_currency: false, + transferability: CrossChainTransferability::Xcm(XcmMetadata { + fee_per_second: None, + }), + }, + }, + ), + ] } } } mod orml_tokens_migration { - use cfg_primitives::AccountId; + use cfg_primitives::{AccountId, Balance}; + use cfg_types::tokens::CurrencyId; + use codec::{Decode, Encode}; + #[cfg(feature = "try-runtime")] + use frame_support::ensure; use orml_tokens::AccountData; + use sp_std::vec::Vec; use super::*; + use crate::Runtime; + + const DEPRECATED_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::AUSD; + const NEW_AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); /// As we dropped `CurrencyId::KSM` and `CurrencyId::AUSD`, we need to /// migrate the balances under the dropped variants in favour of the new, @@ -261,7 +282,7 @@ mod orml_tokens_migration { fn on_runtime_upgrade() -> Weight { use frame_support::traits::tokens::fungibles::Mutate; - let mut migrated_entries = 0; + let mut migrated_entries: u64 = 0; // Burn all AUSD tokens under the old CurrencyId and mint them under the new one orml_tokens::Accounts::::iter() @@ -304,63 +325,31 @@ mod orml_tokens_migration { // Approximate weight given for every entry migration there are two calls being // made, so counting the reads and writes for each call. - ::DbWeight::get() - .reads_writes(migrated_entries * 5, migrated_entries * 4) + ::DbWeight::get().reads_writes( + migrated_entries.saturating_mul(5), + migrated_entries.saturating_mul(4), + ) } } } -mod pool_system { - #[cfg(feature = "try-runtime")] - use cfg_primitives::PoolId; - use pallet_pool_system::pool_types::PoolDetails; - +mod xcm_v2_to_v3 { use super::*; + use crate::{PolkadotXcm, RuntimeOrigin}; - pub struct MigrateAUSDPools; + pub struct SetSafeXcmVersion; - impl OnRuntimeUpgrade for MigrateAUSDPools { + impl OnRuntimeUpgrade for SetSafeXcmVersion { fn on_runtime_upgrade() -> Weight { - pallet_pool_system::Pool::::translate( - |_, mut details: PoolDetails| { - if details.currency == DEPRECATED_AUSD_CURRENCY_ID { - details.currency = NEW_AUSD_CURRENCY_ID; - } - - Some(details) - }, - ); - - let n = pallet_pool_system::Pool::::iter().count() as u64; - ::DbWeight::get().reads_writes(n, n) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - let ausd_pools: Vec = pallet_pool_system::Pool::::iter() - .filter(|(_, details)| details.currency == DEPRECATED_AUSD_CURRENCY_ID) - .map(|(pool_id, _)| pool_id) - .collect::<_>(); - - Ok(ausd_pools.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), &'static str> { - let ausd_pools = sp_std::vec::Vec::::decode(&mut state.as_ref()) - .map_err(|_| "Error decoding pre-upgrade state")?; - - for pool_id in ausd_pools { - let pool = pallet_pool_system::Pool::::get(pool_id) - .expect("AUSD Pool should exist after the migration was executed"); - - ensure!( - pool.currency == NEW_AUSD_CURRENCY_ID, - "A AUSD pool was NOT migrated to the new AUSD CurrencyId (ForeignAsset(2))", - ) - } - - Ok(()) + // Unfortunately, SafeXcmVersion storage is not leaked to runtime, so we can't + // do any pre- or post-upgrade checks + PolkadotXcm::force_default_xcm_version( + RuntimeOrigin::root(), + Some(cfg_primitives::SAFE_XCM_VERSION), + ) + .unwrap_or_else(|_| log::error!("Failed to set safe XCM version on runtime upgrade, requires manual call via governance")); + + crate::RocksDbWeight::get().writes(1) } } } diff --git a/runtime/altair/src/weights/frame_system.rs b/runtime/altair/src/weights/frame_system.rs index f7769e6897..108fc35248 100644 --- a/runtime/altair/src/weights/frame_system.rs +++ b/runtime/altair/src/weights/frame_system.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -32,51 +33,75 @@ pub struct WeightInfo(PhantomData); impl frame_system::WeightInfo for WeightInfo { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { - // Minimum execution time: 9_700 nanoseconds. - Weight::from_ref_time(157_778_032) - // Standard Error: 6 - .saturating_add(Weight::from_ref_time(492).saturating_mul(b.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_096 nanoseconds. + Weight::from_ref_time(4_025_510) + // Standard Error: 0 + .saturating_add(Weight::from_ref_time(310).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - // Minimum execution time: 22_800 nanoseconds. - Weight::from_ref_time(228_602_672) - // Standard Error: 6 - .saturating_add(Weight::from_ref_time(2_041).saturating_mul(b.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_021 nanoseconds. + Weight::from_ref_time(79_690_232) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_779).saturating_mul(b.into())) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a686561707061676573] (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { - // Minimum execution time: 14_800 nanoseconds. - Weight::from_ref_time(15_200_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `495` + // Minimum execution time: 6_031 nanoseconds. + Weight::from_parts(6_403_000, 495) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - // Minimum execution time: 6_700 nanoseconds. - Weight::from_ref_time(6_800_000) - // Standard Error: 2_889 - .saturating_add(Weight::from_ref_time(1_087_067).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_156 nanoseconds. + Weight::from_ref_time(3_296_000) + // Standard Error: 2_320 + .saturating_add(Weight::from_ref_time(885_296).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - // Minimum execution time: 6_800 nanoseconds. - Weight::from_ref_time(7_100_000) - // Standard Error: 1_058 - .saturating_add(Weight::from_ref_time(758_575).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_226 nanoseconds. + Weight::from_ref_time(3_356_000) + // Standard Error: 851 + .saturating_add(Weight::from_ref_time(634_566).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - // Minimum execution time: 12_900 nanoseconds. - Weight::from_ref_time(13_101_000) - // Standard Error: 1_252 - .saturating_add(Weight::from_ref_time(1_398_783).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `149 + p * (69 ±0)` + // Estimated: `139 + p * (70 ±0)` + // Minimum execution time: 6_212 nanoseconds. + Weight::from_parts(6_392_000, 139) + // Standard Error: 1_225 + .saturating_add(Weight::from_ref_time(1_283_115).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) } } diff --git a/runtime/altair/src/weights/pallet_anchors.rs b/runtime/altair/src/weights/pallet_anchors.rs index 9da3b77769..edce84e2d8 100644 --- a/runtime/altair/src/weights/pallet_anchors.rs +++ b/runtime/altair/src/weights/pallet_anchors.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_anchors` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,247 +31,479 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_anchors`. pub struct WeightInfo(PhantomData); impl pallet_anchors::WeightInfo for WeightInfo { - // Storage: Anchor AnchorEvictDates (r:1 w:0) - // Storage: Anchor PreCommits (r:1 w:1) - // Storage: Fees FeeBalances (r:1 w:0) + /// Storage: Anchor AnchorEvictDates (r:1 w:0) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn pre_commit() -> Weight { - // Minimum execution time: 55_001 nanoseconds. - Weight::from_ref_time(55_901_000) + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `7625` + // Minimum execution time: 33_883 nanoseconds. + Weight::from_parts(34_605_000, 7625) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Timestamp Now (r:1 w:0) - // Storage: Anchor AnchorEvictDates (r:1 w:1) - // Storage: Anchor PreCommits (r:1 w:1) - // Storage: Fees FeeBalances (r:1 w:0) - // Storage: Authorship Author (r:1 w:0) - // Storage: System Digest (r:1 w:0) - // Storage: Anchor LatestAnchorIndex (r:1 w:1) - // Storage: Anchor AnchorIndexes (r:0 w:1) - // Storage: unknown [0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9] (r:0 w:1) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:1 w:1) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Authorship Author (r:1 w:0) + /// Proof: Authorship Author (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: System Digest (r:1 w:0) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Anchor LatestAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:0 w:1) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) + /// Proof Skipped: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) fn commit() -> Weight { - // Minimum execution time: 86_302 nanoseconds. - Weight::from_ref_time(87_502_000) + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `11053` + // Minimum execution time: 64_250 nanoseconds. + Weight::from_parts(65_582_000, 11053) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: Anchor PreCommits (r:100 w:100) + /// Storage: Anchor PreCommits (r:100 w:100) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) fn evict_pre_commits() -> Weight { - // Minimum execution time: 1_867_131 nanoseconds. - Weight::from_ref_time(1_888_832_000) + // Proof Size summary in bytes: + // Measured: `15750` + // Estimated: `259100` + // Minimum execution time: 1_711_580 nanoseconds. + Weight::from_parts(1_726_909_000, 259100) .saturating_add(T::DbWeight::get().reads(100)) .saturating_add(T::DbWeight::get().writes(100)) } - // Storage: Timestamp Now (r:1 w:0) - // Storage: Anchor LatestEvictedDate (r:1 w:1) - // Storage: Anchor EvictedAnchorRoots (r:100 w:100) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000] (r:1 w:0) - // Storage: Anchor LatestEvictedAnchorIndex (r:1 w:1) - // Storage: Anchor LatestAnchorIndex (r:1 w:0) - // Storage: Anchor AnchorIndexes (r:100 w:100) - // Storage: Anchor AnchorEvictDates (r:100 w:100) - // Storage: unknown [0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f] (r:0 w:1) - // Storage: unknown [0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704] (r:0 w:1) - // Storage: unknown [0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3] (r:0 w:1) - // Storage: unknown [0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a] (r:0 w:1) - // Storage: unknown [0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c] (r:0 w:1) - // Storage: unknown [0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856] (r:0 w:1) - // Storage: unknown [0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e] (r:0 w:1) - // Storage: unknown [0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff] (r:0 w:1) - // Storage: unknown [0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8] (r:0 w:1) - // Storage: unknown [0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed] (r:0 w:1) - // Storage: unknown [0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f] (r:0 w:1) - // Storage: unknown [0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464] (r:0 w:1) - // Storage: unknown [0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde] (r:0 w:1) - // Storage: unknown [0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a] (r:0 w:1) - // Storage: unknown [0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380] (r:0 w:1) - // Storage: unknown [0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84] (r:0 w:1) - // Storage: unknown [0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f] (r:0 w:1) - // Storage: unknown [0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5] (r:0 w:1) - // Storage: unknown [0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf] (r:0 w:1) - // Storage: unknown [0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea] (r:0 w:1) - // Storage: unknown [0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2] (r:0 w:1) - // Storage: unknown [0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e] (r:0 w:1) - // Storage: unknown [0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df] (r:0 w:1) - // Storage: unknown [0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0] (r:0 w:1) - // Storage: unknown [0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b] (r:0 w:1) - // Storage: unknown [0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b] (r:0 w:1) - // Storage: unknown [0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9] (r:0 w:1) - // Storage: unknown [0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775] (r:0 w:1) - // Storage: unknown [0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906] (r:0 w:1) - // Storage: unknown [0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5] (r:0 w:1) - // Storage: unknown [0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0] (r:0 w:1) - // Storage: unknown [0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17] (r:0 w:1) - // Storage: unknown [0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8] (r:0 w:1) - // Storage: unknown [0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644] (r:0 w:1) - // Storage: unknown [0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90] (r:0 w:1) - // Storage: unknown [0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9] (r:0 w:1) - // Storage: unknown [0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287] (r:0 w:1) - // Storage: unknown [0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0] (r:0 w:1) - // Storage: unknown [0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403] (r:0 w:1) - // Storage: unknown [0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2] (r:0 w:1) - // Storage: unknown [0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044] (r:0 w:1) - // Storage: unknown [0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec] (r:0 w:1) - // Storage: unknown [0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e] (r:0 w:1) - // Storage: unknown [0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1] (r:0 w:1) - // Storage: unknown [0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55] (r:0 w:1) - // Storage: unknown [0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0] (r:0 w:1) - // Storage: unknown [0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820] (r:0 w:1) - // Storage: unknown [0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7] (r:0 w:1) - // Storage: unknown [0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329] (r:0 w:1) - // Storage: unknown [0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0] (r:0 w:1) - // Storage: unknown [0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0] (r:0 w:1) - // Storage: unknown [0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256] (r:0 w:1) - // Storage: unknown [0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773] (r:0 w:1) - // Storage: unknown [0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826] (r:0 w:1) - // Storage: unknown [0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6] (r:0 w:1) - // Storage: unknown [0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc] (r:0 w:1) - // Storage: unknown [0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75] (r:0 w:1) - // Storage: unknown [0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5] (r:0 w:1) - // Storage: unknown [0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17] (r:0 w:1) - // Storage: unknown [0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce] (r:0 w:1) - // Storage: unknown [0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956] (r:0 w:1) - // Storage: unknown [0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c] (r:0 w:1) - // Storage: unknown [0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1] (r:0 w:1) - // Storage: unknown [0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb] (r:0 w:1) - // Storage: unknown [0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56] (r:0 w:1) - // Storage: unknown [0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78] (r:0 w:1) - // Storage: unknown [0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987] (r:0 w:1) - // Storage: unknown [0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013] (r:0 w:1) - // Storage: unknown [0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d] (r:0 w:1) - // Storage: unknown [0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58] (r:0 w:1) - // Storage: unknown [0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad] (r:0 w:1) - // Storage: unknown [0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136] (r:0 w:1) - // Storage: unknown [0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb] (r:0 w:1) - // Storage: unknown [0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0] (r:0 w:1) - // Storage: unknown [0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561] (r:0 w:1) - // Storage: unknown [0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd] (r:0 w:1) - // Storage: unknown [0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a] (r:0 w:1) - // Storage: unknown [0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b] (r:0 w:1) - // Storage: unknown [0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2] (r:0 w:1) - // Storage: unknown [0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5] (r:0 w:1) - // Storage: unknown [0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c] (r:0 w:1) - // Storage: unknown [0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362] (r:0 w:1) - // Storage: unknown [0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc] (r:0 w:1) - // Storage: unknown [0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7] (r:0 w:1) - // Storage: unknown [0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58] (r:0 w:1) - // Storage: unknown [0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f] (r:0 w:1) - // Storage: unknown [0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171] (r:0 w:1) - // Storage: unknown [0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63] (r:0 w:1) - // Storage: unknown [0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b] (r:0 w:1) - // Storage: unknown [0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a] (r:0 w:1) - // Storage: unknown [0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f] (r:0 w:1) - // Storage: unknown [0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b] (r:0 w:1) - // Storage: unknown [0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a] (r:0 w:1) - // Storage: unknown [0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e] (r:0 w:1) - // Storage: unknown [0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1] (r:0 w:1) - // Storage: unknown [0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8] (r:0 w:1) - // Storage: unknown [0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c] (r:0 w:1) - // Storage: unknown [0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48] (r:0 w:1) - // Storage: unknown [0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b] (r:0 w:1) - // Storage: unknown [0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312] (r:0 w:1) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestEvictedDate (r:1 w:1) + /// Proof: Anchor LatestEvictedDate (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Anchor EvictedAnchorRoots (r:100 w:100) + /// Proof: Anchor EvictedAnchorRoots (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Storage: Anchor LatestEvictedAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestEvictedAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestAnchorIndex (r:1 w:0) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:100 w:100) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:100 w:100) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Proof Skipped: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Storage: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Proof Skipped: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Storage: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Proof Skipped: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Storage: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Proof Skipped: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Storage: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Proof Skipped: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Storage: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Proof Skipped: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Storage: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Proof Skipped: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Storage: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Proof Skipped: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Storage: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Proof Skipped: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Storage: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Proof Skipped: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Storage: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Proof Skipped: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Storage: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Proof Skipped: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Storage: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Proof Skipped: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Storage: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Proof Skipped: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Storage: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Proof Skipped: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Storage: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Proof Skipped: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Storage: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Proof Skipped: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Storage: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Proof Skipped: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Storage: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Proof Skipped: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Storage: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Proof Skipped: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Storage: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Proof Skipped: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Storage: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Proof Skipped: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Storage: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Proof Skipped: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Storage: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Proof Skipped: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Storage: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Proof Skipped: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Storage: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Proof Skipped: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Storage: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Proof Skipped: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Storage: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Proof Skipped: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Storage: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Proof Skipped: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Storage: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Proof Skipped: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Storage: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Proof Skipped: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Storage: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Proof Skipped: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Storage: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Proof Skipped: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Storage: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Proof Skipped: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Storage: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Proof Skipped: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Storage: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Proof Skipped: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Storage: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Proof Skipped: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Storage: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Proof Skipped: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Storage: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Proof Skipped: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Storage: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Proof Skipped: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Storage: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Proof Skipped: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Storage: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Proof Skipped: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Storage: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Proof Skipped: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Storage: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Proof Skipped: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Storage: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Proof Skipped: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Storage: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Storage: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Proof Skipped: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Storage: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Proof Skipped: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Storage: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Proof Skipped: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Storage: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Proof Skipped: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Storage: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Storage: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Proof Skipped: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Storage: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Proof Skipped: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Storage: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Proof Skipped: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Storage: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Proof Skipped: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Storage: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Proof Skipped: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Storage: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Proof Skipped: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Storage: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Proof Skipped: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Storage: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Proof Skipped: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Storage: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Proof Skipped: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Storage: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Proof Skipped: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Storage: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Proof Skipped: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Storage: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Proof Skipped: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Storage: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Proof Skipped: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Storage: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Proof Skipped: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Storage: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Proof Skipped: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Storage: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Proof Skipped: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Storage: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Proof Skipped: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Storage: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Proof Skipped: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Storage: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Proof Skipped: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Storage: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Proof Skipped: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Storage: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Proof Skipped: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Storage: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Proof Skipped: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Storage: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Proof Skipped: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Storage: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Proof Skipped: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Storage: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Proof Skipped: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Storage: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Proof Skipped: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Storage: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Proof Skipped: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Storage: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Proof Skipped: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Storage: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Proof Skipped: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Storage: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Proof Skipped: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Storage: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Proof Skipped: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Storage: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Proof Skipped: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Storage: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Proof Skipped: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Storage: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Proof Skipped: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Storage: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Proof Skipped: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Storage: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Proof Skipped: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Storage: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Proof Skipped: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Storage: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Proof Skipped: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Storage: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Proof Skipped: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Storage: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Proof Skipped: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Storage: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Proof Skipped: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Storage: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Proof Skipped: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Storage: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Proof Skipped: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Storage: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Proof Skipped: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Storage: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Proof Skipped: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Storage: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Proof Skipped: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Storage: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Proof Skipped: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Storage: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Proof Skipped: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Storage: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) + /// Proof Skipped: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) fn evict_anchors() -> Weight { - // Minimum execution time: 2_066_334 nanoseconds. - Weight::from_ref_time(2_079_434_000) + // Proof Size summary in bytes: + // Measured: `18358` + // Estimated: `4680108` + // Minimum execution time: 1_897_557 nanoseconds. + Weight::from_parts(1_918_918_000, 4680108) .saturating_add(T::DbWeight::get().reads(404)) .saturating_add(T::DbWeight::get().writes(402)) } diff --git a/runtime/altair/src/weights/pallet_balances.rs b/runtime/altair/src/weights/pallet_balances.rs index 296d0ec05a..e1d1d2e72e 100644 --- a/runtime/altair/src/weights/pallet_balances.rs +++ b/runtime/altair/src/weights/pallet_balances.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,52 +31,80 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 77_302 nanoseconds. - Weight::from_ref_time(78_801_000) + // Proof Size summary in bytes: + // Measured: `1825` + // Estimated: `2603` + // Minimum execution time: 71_924 nanoseconds. + Weight::from_parts(74_018_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // Minimum execution time: 56_901 nanoseconds. - Weight::from_ref_time(57_701_000) + // Proof Size summary in bytes: + // Measured: `1534` + // Estimated: `2603` + // Minimum execution time: 51_055 nanoseconds. + Weight::from_parts(52_338_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { - // Minimum execution time: 43_701 nanoseconds. - Weight::from_ref_time(44_501_000) + // Proof Size summary in bytes: + // Measured: `1859` + // Estimated: `2603` + // Minimum execution time: 39_304 nanoseconds. + Weight::from_parts(40_676_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { - // Minimum execution time: 48_301 nanoseconds. - Weight::from_ref_time(49_701_000) + // Proof Size summary in bytes: + // Measured: `1859` + // Estimated: `2603` + // Minimum execution time: 44_754 nanoseconds. + Weight::from_parts(45_765_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:2 w:2) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // Minimum execution time: 77_802 nanoseconds. - Weight::from_ref_time(78_701_000) + // Proof Size summary in bytes: + // Measured: `1825` + // Estimated: `5206` + // Minimum execution time: 72_135 nanoseconds. + Weight::from_parts(73_447_000, 5206) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { - // Minimum execution time: 66_201 nanoseconds. - Weight::from_ref_time(67_101_000) + // Proof Size summary in bytes: + // Measured: `1534` + // Estimated: `2603` + // Minimum execution time: 61_074 nanoseconds. + Weight::from_parts(62_066_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { - // Minimum execution time: 35_901 nanoseconds. - Weight::from_ref_time(37_501_000) + // Proof Size summary in bytes: + // Measured: `1568` + // Estimated: `2603` + // Minimum execution time: 32_360 nanoseconds. + Weight::from_parts(32_941_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_block_rewards.rs b/runtime/altair/src/weights/pallet_block_rewards.rs index 7f9458ad0e..bbb7608492 100644 --- a/runtime/altair/src/weights/pallet_block_rewards.rs +++ b/runtime/altair/src/weights/pallet_block_rewards.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_block_rewards` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,29 +31,46 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_block_rewards`. pub struct WeightInfo(PhantomData); impl pallet_block_rewards::WeightInfo for WeightInfo { - // Storage: BlockRewardsBase Currency (r:1 w:0) - // Storage: BlockRewardsBase Group (r:1 w:0) - // Storage: BlockRewardsBase StakeAccount (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: BlockRewardsBase Currency (r:1 w:0) + /// Proof: BlockRewardsBase Currency (max_values: None, max_size: Some(79), added: 2554, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase Group (r:1 w:0) + /// Proof: BlockRewardsBase Group (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase StakeAccount (r:1 w:1) + /// Proof: BlockRewardsBase StakeAccount (max_values: None, max_size: Some(123), added: 2598, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_reward() -> Weight { - // Minimum execution time: 84_001 nanoseconds. - Weight::from_ref_time(84_901_000) + // Proof Size summary in bytes: + // Measured: `678` + // Estimated: `12885` + // Minimum execution time: 59_271 nanoseconds. + Weight::from_parts(59_792_000, 12885) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) - // Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_collator_reward() -> Weight { - // Minimum execution time: 18_200 nanoseconds. - Weight::from_ref_time(18_700_000) + // Proof Size summary in bytes: + // Measured: `138` + // Estimated: `3115` + // Minimum execution time: 12_222 nanoseconds. + Weight::from_parts(12_944_000, 3115) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) - // Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_total_reward() -> Weight { - // Minimum execution time: 16_600 nanoseconds. - Weight::from_ref_time(17_200_000) + // Proof Size summary in bytes: + // Measured: `97` + // Estimated: `3115` + // Minimum execution time: 11_221 nanoseconds. + Weight::from_parts(11_522_000, 3115) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_collator_allowlist.rs b/runtime/altair/src/weights/pallet_collator_allowlist.rs index 84c812d134..bdde6be795 100644 --- a/runtime/altair/src/weights/pallet_collator_allowlist.rs +++ b/runtime/altair/src/weights/pallet_collator_allowlist.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_collator_allowlist` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,18 +31,27 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collator_allowlist`. pub struct WeightInfo(PhantomData); impl pallet_collator_allowlist::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn add() -> Weight { - // Minimum execution time: 38_601 nanoseconds. - Weight::from_ref_time(39_301_000) + // Proof Size summary in bytes: + // Measured: `457` + // Estimated: `5439` + // Minimum execution time: 25_738 nanoseconds. + Weight::from_parts(26_549_000, 5439) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn remove() -> Weight { - // Minimum execution time: 30_501 nanoseconds. - Weight::from_ref_time(31_101_000) + // Proof Size summary in bytes: + // Measured: `133` + // Estimated: `2507` + // Minimum execution time: 18_725 nanoseconds. + Weight::from_parts(19_396_000, 2507) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_collator_selection.rs b/runtime/altair/src/weights/pallet_collator_selection.rs index 931d63b123..17eb6d8e62 100644 --- a/runtime/altair/src/weights/pallet_collator_selection.rs +++ b/runtime/altair/src/weights/pallet_collator_selection.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,81 +31,128 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - // Storage: CollatorAllowlist Allowlist (r:1 w:0) - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Storage: CollatorAllowlist Allowlist (r:100 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:100 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) /// The range of component `b` is `[1, 100]`. fn set_invulnerables(b: u32, ) -> Weight { - // Minimum execution time: 41_501 nanoseconds. - Weight::from_ref_time(43_594_397) - // Standard Error: 7_792 - .saturating_add(Weight::from_ref_time(6_194_704).saturating_mul(b.into())) + // Proof Size summary in bytes: + // Measured: `367 + b * (144 ±0)` + // Estimated: `364 + b * (5127 ±0)` + // Minimum execution time: 25_928 nanoseconds. + Weight::from_parts(25_122_329, 364) + // Standard Error: 7_006 + .saturating_add(Weight::from_ref_time(5_788_548).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(5127).saturating_mul(b.into())) } - // Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_desired_candidates() -> Weight { - // Minimum execution time: 25_600 nanoseconds. - Weight::from_ref_time(26_401_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 15_408 nanoseconds. + Weight::from_ref_time(16_001_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_candidacy_bond() -> Weight { - // Minimum execution time: 22_301 nanoseconds. - Weight::from_ref_time(22_601_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_540 nanoseconds. + Weight::from_ref_time(19_045_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection DesiredCandidates (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: CollatorAllowlist Allowlist (r:1 w:0) - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection CandidacyBond (r:1 w:0) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection DesiredCandidates (r:1 w:0) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: CollatorAllowlist Allowlist (r:1 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection CandidacyBond (r:1 w:0) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) /// The range of component `c` is `[1, 99]`. fn register_as_candidate(c: u32, ) -> Weight { - // Minimum execution time: 85_801 nanoseconds. - Weight::from_ref_time(94_457_751) - // Standard Error: 3_896 - .saturating_add(Weight::from_ref_time(290_979).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `1154 + c * (52 ±0)` + // Estimated: `16089 + c * (53 ±0)` + // Minimum execution time: 59_161 nanoseconds. + Weight::from_parts(62_567_481, 16089) + // Standard Error: 1_512 + .saturating_add(Weight::from_ref_time(129_374).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(53).saturating_mul(c.into())) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) /// The range of component `c` is `[6, 100]`. fn leave_intent(c: u32, ) -> Weight { - // Minimum execution time: 59_501 nanoseconds. - Weight::from_ref_time(63_375_946) - // Standard Error: 3_389 - .saturating_add(Weight::from_ref_time(232_088).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `430 + c * (49 ±0)` + // Estimated: `5297` + // Minimum execution time: 38_923 nanoseconds. + Weight::from_parts(39_334_912, 5297) + // Standard Error: 1_942 + .saturating_add(Weight::from_ref_time(130_796).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:2 w:2) - // Storage: System BlockWeight (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { - // Minimum execution time: 59_301 nanoseconds. - Weight::from_ref_time(60_101_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `5749` + // Minimum execution time: 42_940 nanoseconds. + Weight::from_parts(43_702_000, 5749) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:100 w:1) - // Storage: System Account (r:1 w:1) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: System BlockWeight (r:1 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:0) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:100 w:0) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: System Account (r:95 w:95) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. /// The range of component `c` is `[1, 100]`. - fn new_session(_r: u32, c: u32, ) -> Weight { - // Minimum execution time: 36_101 nanoseconds. - Weight::from_ref_time(36_401_000) - // Standard Error: 466_215 - .saturating_add(Weight::from_ref_time(17_679_837).saturating_mul(c.into())) + fn new_session(r: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2629 + r * (147 ±0) + c * (97 ±0)` + // Estimated: `9537 + c * (2521 ±0) + r * (2597 ±1)` + // Minimum execution time: 25_738 nanoseconds. + Weight::from_parts(26_209_000, 9537) + // Standard Error: 413_029 + .saturating_add(Weight::from_ref_time(15_662_996).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(2521).saturating_mul(c.into())) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(r.into())) } } diff --git a/runtime/altair/src/weights/pallet_collective.rs b/runtime/altair/src/weights/pallet_collective.rs index a65d780224..14310adda7 100644 --- a/runtime/altair/src/weights/pallet_collective.rs +++ b/runtime/altair/src/weights/pallet_collective.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,163 +31,246 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collective`. pub struct WeightInfo(PhantomData); impl pallet_collective::WeightInfo for WeightInfo { - // Storage: Council Members (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Prime (r:0 w:1) - // Storage: Council Voting (r:100 w:100) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Minimum execution time: 27_500 nanoseconds. - Weight::from_ref_time(27_700_000) - // Standard Error: 96_703 - .saturating_add(Weight::from_ref_time(7_660_377).saturating_mul(m.into())) - // Standard Error: 96_703 - .saturating_add(Weight::from_ref_time(11_872_341).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` + // Estimated: `16190 + m * (7809 ±23) + p * (10238 ±23)` + // Minimum execution time: 23_134 nanoseconds. + Weight::from_parts(23_594_000, 16190) + // Standard Error: 61_015 + .saturating_add(Weight::from_ref_time(4_595_291).saturating_mul(m.into())) + // Standard Error: 61_015 + .saturating_add(Weight::from_ref_time(8_686_680).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 35_201 nanoseconds. - Weight::from_ref_time(33_777_344) - // Standard Error: 842 - .saturating_add(Weight::from_ref_time(1_277).saturating_mul(b.into())) - // Standard Error: 8_683 - .saturating_add(Weight::from_ref_time(61_049).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `631 + m * (32 ±0)` + // Minimum execution time: 25_929 nanoseconds. + Weight::from_parts(25_120_355, 631) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(1_657).saturating_mul(b.into())) + // Standard Error: 424 + .saturating_add(Weight::from_ref_time(24_570).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:0) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 39_301 nanoseconds. - Weight::from_ref_time(38_339_800) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(1_917).saturating_mul(b.into())) - // Standard Error: 785 - .saturating_add(Weight::from_ref_time(27_479).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `3242 + m * (64 ±0)` + // Minimum execution time: 28_854 nanoseconds. + Weight::from_parts(27_971_770, 3242) + // Standard Error: 68 + .saturating_add(Weight::from_ref_time(1_713).saturating_mul(b.into())) + // Standard Error: 701 + .saturating_add(Weight::from_ref_time(31_532).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalCount (r:1 w:1) - // Storage: Council Voting (r:0 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 49_501 nanoseconds. - Weight::from_ref_time(49_460_913) - // Standard Error: 211 - .saturating_add(Weight::from_ref_time(5_715).saturating_mul(b.into())) - // Standard Error: 2_209 - .saturating_add(Weight::from_ref_time(41_038).saturating_mul(m.into())) - // Standard Error: 2_181 - .saturating_add(Weight::from_ref_time(306_744).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `457 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `5860 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 37_069 nanoseconds. + Weight::from_parts(37_767_213, 5860) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(2_563).saturating_mul(b.into())) + // Standard Error: 1_800 + .saturating_add(Weight::from_ref_time(24_282).saturating_mul(m.into())) + // Standard Error: 1_777 + .saturating_add(Weight::from_ref_time(201_986).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council Voting (r:1 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 54_201 nanoseconds. - Weight::from_ref_time(56_713_970) - // Standard Error: 1_657 - .saturating_add(Weight::from_ref_time(61_280).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `907 + m * (64 ±0)` + // Estimated: `4782 + m * (128 ±0)` + // Minimum execution time: 31_579 nanoseconds. + Weight::from_parts(32_318_521, 4782) + // Standard Error: 677 + .saturating_add(Weight::from_ref_time(42_587).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 51_901 nanoseconds. - Weight::from_ref_time(57_046_931) - // Standard Error: 1_764 - .saturating_add(Weight::from_ref_time(29_782).saturating_mul(m.into())) - // Standard Error: 1_720 - .saturating_add(Weight::from_ref_time(261_620).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `527 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `5497 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 39_384 nanoseconds. + Weight::from_parts(41_119_503, 5497) + // Standard Error: 1_090 + .saturating_add(Weight::from_ref_time(27_119).saturating_mul(m.into())) + // Standard Error: 1_063 + .saturating_add(Weight::from_ref_time(187_910).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 70_601 nanoseconds. - Weight::from_ref_time(72_820_158) - // Standard Error: 190 - .saturating_add(Weight::from_ref_time(3_860).saturating_mul(b.into())) - // Standard Error: 2_011 - .saturating_add(Weight::from_ref_time(35_271).saturating_mul(m.into())) - // Standard Error: 1_960 - .saturating_add(Weight::from_ref_time(298_880).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `863 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `8768 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 59_131 nanoseconds. + Weight::from_parts(61_240_411, 8768) + // Standard Error: 237 + .saturating_add(Weight::from_ref_time(1_888).saturating_mul(b.into())) + // Standard Error: 2_506 + .saturating_add(Weight::from_ref_time(4_915).saturating_mul(m.into())) + // Standard Error: 2_443 + .saturating_add(Weight::from_ref_time(234_963).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Prime (r:1 w:0) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 57_301 nanoseconds. - Weight::from_ref_time(59_700_919) - // Standard Error: 1_932 - .saturating_add(Weight::from_ref_time(45_190).saturating_mul(m.into())) - // Standard Error: 1_884 - .saturating_add(Weight::from_ref_time(266_951).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `547 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `6600 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 44_082 nanoseconds. + Weight::from_parts(43_758_856, 6600) + // Standard Error: 1_459 + .saturating_add(Weight::from_ref_time(40_000).saturating_mul(m.into())) + // Standard Error: 1_423 + .saturating_add(Weight::from_ref_time(192_888).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Prime (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 74_602 nanoseconds. - Weight::from_ref_time(76_928_781) - // Standard Error: 222 - .saturating_add(Weight::from_ref_time(4_416).saturating_mul(b.into())) - // Standard Error: 2_352 - .saturating_add(Weight::from_ref_time(30_772).saturating_mul(m.into())) - // Standard Error: 2_292 - .saturating_add(Weight::from_ref_time(300_996).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `883 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `10070 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 61_566 nanoseconds. + Weight::from_parts(63_366_092, 10070) + // Standard Error: 188 + .saturating_add(Weight::from_ref_time(2_948).saturating_mul(b.into())) + // Standard Error: 1_987 + .saturating_add(Weight::from_ref_time(29_392).saturating_mul(m.into())) + // Standard Error: 1_936 + .saturating_add(Weight::from_ref_time(233_267).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) } - // Storage: Council Proposals (r:1 w:1) - // Storage: Council Voting (r:0 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // Minimum execution time: 33_801 nanoseconds. - Weight::from_ref_time(39_390_691) - // Standard Error: 2_885 - .saturating_add(Weight::from_ref_time(283_719).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `292 + p * (32 ±0)` + // Estimated: `1371 + p * (96 ±0)` + // Minimum execution time: 23_494 nanoseconds. + Weight::from_parts(25_469_741, 1371) + // Standard Error: 758 + .saturating_add(Weight::from_ref_time(195_589).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) } } diff --git a/runtime/altair/src/weights/pallet_crowdloan_claim.rs b/runtime/altair/src/weights/pallet_crowdloan_claim.rs index 93ad5fb628..5d55e540c9 100644 --- a/runtime/altair/src/weights/pallet_crowdloan_claim.rs +++ b/runtime/altair/src/weights/pallet_crowdloan_claim.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_crowdloan_claim` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,98 +31,170 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_crowdloan_claim`. pub struct WeightInfo(PhantomData); impl pallet_crowdloan_claim::WeightInfo for WeightInfo { - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ed25519() -> Weight { - // Minimum execution time: 250_904 nanoseconds. - Weight::from_ref_time(253_704_000) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `18561` + // Minimum execution time: 207_559 nanoseconds. + Weight::from_parts(209_652_000, 18561) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_sr25519() -> Weight { - // Minimum execution time: 255_004 nanoseconds. - Weight::from_ref_time(256_804_000) + // Proof Size summary in bytes: + // Measured: `658` + // Estimated: `18561` + // Minimum execution time: 212_598 nanoseconds. + Weight::from_parts(214_701_000, 18561) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ecdsa() -> Weight { - // Minimum execution time: 234_203 nanoseconds. - Weight::from_ref_time(236_204_000) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `18561` + // Minimum execution time: 192_821 nanoseconds. + Weight::from_parts(194_143_000, 18561) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:1) - // Storage: CrowdloanClaim LeaseStart (r:1 w:1) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:1) - // Storage: CrowdloanClaim PrevIndex (r:1 w:0) - // Storage: CrowdloanClaim Contributions (r:0 w:1) - // Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) - // Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:1) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim PrevIndex (r:1 w:0) + /// Proof: CrowdloanClaim PrevIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - // Minimum execution time: 37_101 nanoseconds. - Weight::from_ref_time(37_901_000) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1996` + // Minimum execution time: 24_076 nanoseconds. + Weight::from_parts(24_667_000, 1996) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: CrowdloanClaim LeaseStart (r:0 w:1) + /// Storage: CrowdloanClaim LeaseStart (r:0 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_start() -> Weight { - // Minimum execution time: 22_300 nanoseconds. - Weight::from_ref_time(22_701_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_151 nanoseconds. + Weight::from_ref_time(11_482_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim LeasePeriod (r:0 w:1) + /// Storage: CrowdloanClaim LeasePeriod (r:0 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_period() -> Weight { - // Minimum execution time: 22_400 nanoseconds. - Weight::from_ref_time(22_801_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_981 nanoseconds. + Weight::from_ref_time(11_492_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) fn set_contributions_root() -> Weight { - // Minimum execution time: 23_900 nanoseconds. - Weight::from_ref_time(24_801_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_113 nanoseconds. + Weight::from_ref_time(12_673_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_locked_at() -> Weight { - // Minimum execution time: 22_200 nanoseconds. - Weight::from_ref_time(22_800_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_970 nanoseconds. + Weight::from_ref_time(11_431_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_crowdloan_trie_index() -> Weight { - // Minimum execution time: 22_100 nanoseconds. - Weight::from_ref_time(22_600_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_120 nanoseconds. + Weight::from_ref_time(11_482_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/altair/src/weights/pallet_crowdloan_reward.rs b/runtime/altair/src/weights/pallet_crowdloan_reward.rs index 05c1736aa6..927e88a88b 100644 --- a/runtime/altair/src/weights/pallet_crowdloan_reward.rs +++ b/runtime/altair/src/weights/pallet_crowdloan_reward.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_crowdloan_reward` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,30 +31,48 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_crowdloan_reward`. pub struct WeightInfo(PhantomData); impl pallet_crowdloan_reward::WeightInfo for WeightInfo { - // Storage: CrowdloanReward VestingStart (r:0 w:1) - // Storage: CrowdloanReward VestingPeriod (r:0 w:1) - // Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - // Minimum execution time: 24_201 nanoseconds. - Weight::from_ref_time(24_900_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_854 nanoseconds. + Weight::from_ref_time(13_275_000) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_start() -> Weight { - // Minimum execution time: 21_700 nanoseconds. - Weight::from_ref_time(22_300_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_830 nanoseconds. + Weight::from_ref_time(11_371_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_period() -> Weight { - // Minimum execution time: 21_800 nanoseconds. - Weight::from_ref_time(22_201_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_920 nanoseconds. + Weight::from_ref_time(11_321_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_direct_payout_ratio() -> Weight { - // Minimum execution time: 22_001 nanoseconds. - Weight::from_ref_time(22_501_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_991 nanoseconds. + Weight::from_ref_time(11_321_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/altair/src/weights/pallet_democracy.rs b/runtime/altair/src/weights/pallet_democracy.rs index acff9e327c..c371824f26 100644 --- a/runtime/altair/src/weights/pallet_democracy.rs +++ b/runtime/altair/src/weights/pallet_democracy.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_democracy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,218 +31,345 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_democracy`. pub struct WeightInfo(PhantomData); impl pallet_democracy::WeightInfo for WeightInfo { - // Storage: Democracy PublicPropCount (r:1 w:1) - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) - // Storage: Democracy DepositOf (r:0 w:1) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { - // Minimum execution time: 81_802 nanoseconds. - Weight::from_ref_time(84_701_000) + // Proof Size summary in bytes: + // Measured: `4864` + // Estimated: `23409` + // Minimum execution time: 50_855 nanoseconds. + Weight::from_parts(52_598_000, 23409) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy DepositOf (r:1 w:1) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { - // Minimum execution time: 73_202 nanoseconds. - Weight::from_ref_time(74_801_000) + // Proof Size summary in bytes: + // Measured: `3620` + // Estimated: `5705` + // Minimum execution time: 44_944 nanoseconds. + Weight::from_parts(46_337_000, 5705) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { - // Minimum execution time: 95_001 nanoseconds. - Weight::from_ref_time(96_702_000) + // Proof Size summary in bytes: + // Measured: `3517` + // Estimated: `12720` + // Minimum execution time: 58_189 nanoseconds. + Weight::from_parts(59_251_000, 12720) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // Minimum execution time: 94_102 nanoseconds. - Weight::from_ref_time(95_202_000) + // Proof Size summary in bytes: + // Measured: `3539` + // Estimated: `12720` + // Minimum execution time: 57_989 nanoseconds. + Weight::from_parts(59_361_000, 12720) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy Cancellations (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { - // Minimum execution time: 37_300 nanoseconds. - Weight::from_ref_time(49_301_000) + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `5184` + // Minimum execution time: 26_159 nanoseconds. + Weight::from_parts(26_510_000, 5184) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy Blacklist (r:0 w:1) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { - // Minimum execution time: 146_403 nanoseconds. - Weight::from_ref_time(150_102_000) + // Proof Size summary in bytes: + // Measured: `6362` + // Estimated: `31411` + // Minimum execution time: 113_022 nanoseconds. + Weight::from_parts(115_145_000, 31411) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { - // Minimum execution time: 28_101 nanoseconds. - Weight::from_ref_time(28_800_000) + // Proof Size summary in bytes: + // Measured: `3448` + // Estimated: `6340` + // Minimum execution time: 18_575 nanoseconds. + Weight::from_parts(19_106_000, 6340) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:0 w:1) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { - // Minimum execution time: 8_801 nanoseconds. - Weight::from_ref_time(9_100_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_859 nanoseconds. + Weight::from_ref_time(5_290_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:0 w:1) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { - // Minimum execution time: 8_800 nanoseconds. - Weight::from_ref_time(9_100_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_009 nanoseconds. + Weight::from_ref_time(5_340_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { - // Minimum execution time: 37_001 nanoseconds. - Weight::from_ref_time(37_601_000) + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `1126` + // Minimum execution time: 24_576 nanoseconds. + Weight::from_parts(25_257_000, 1126) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:1) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn veto_external() -> Weight { - // Minimum execution time: 45_001 nanoseconds. - Weight::from_ref_time(46_300_000) + // Proof Size summary in bytes: + // Measured: `3477` + // Estimated: `6340` + // Minimum execution time: 30_186 nanoseconds. + Weight::from_parts(30_597_000, 6340) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { - // Minimum execution time: 124_602 nanoseconds. - Weight::from_ref_time(127_502_000) + // Proof Size summary in bytes: + // Measured: `6241` + // Estimated: `28108` + // Minimum execution time: 93_315 nanoseconds. + Weight::from_parts(94_667_000, 28108) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { - // Minimum execution time: 24_300 nanoseconds. - Weight::from_ref_time(24_700_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_474 nanoseconds. + Weight::from_ref_time(13_035_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy LowestUnbaked (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - // Minimum execution time: 11_400 nanoseconds. - Weight::from_ref_time(17_451_496) - // Standard Error: 9_869 - .saturating_add(Weight::from_ref_time(3_804_301).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `998 + r * (2676 ±0)` + // Minimum execution time: 10_109 nanoseconds. + Weight::from_parts(11_920_841, 998) + // Standard Error: 6_222 + .saturating_add(Weight::from_ref_time(3_748_453).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy LowestUnbaked (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy LastTabledWasExternal (r:1 w:0) - // Storage: Democracy NextExternal (r:1 w:0) - // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // Minimum execution time: 20_600 nanoseconds. - Weight::from_ref_time(23_877_265) - // Standard Error: 11_146 - .saturating_add(Weight::from_ref_time(3_778_535).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `19318 + r * (2676 ±0)` + // Minimum execution time: 14_126 nanoseconds. + Weight::from_parts(16_557_721, 19318) + // Standard Error: 6_701 + .saturating_add(Weight::from_ref_time(3_750_449).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Balances Locks (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - // Minimum execution time: 74_601 nanoseconds. - Weight::from_ref_time(79_709_213) - // Standard Error: 38_675 - .saturating_add(Weight::from_ref_time(5_715_955).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `914 + r * (139 ±0)` + // Estimated: `22584 + r * (2676 ±0)` + // Minimum execution time: 48_701 nanoseconds. + Weight::from_parts(54_206_106, 22584) + // Standard Error: 6_965 + .saturating_add(Weight::from_ref_time(4_858_485).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - // Minimum execution time: 43_501 nanoseconds. - Weight::from_ref_time(51_001_565) - // Standard Error: 13_095 - .saturating_add(Weight::from_ref_time(5_520_305).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `547 + r * (139 ±0)` + // Estimated: `12540 + r * (2676 ±0)` + // Minimum execution time: 28_262 nanoseconds. + Weight::from_parts(29_173_029, 12540) + // Standard Error: 6_460 + .saturating_add(Weight::from_ref_time(4_809_713).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy PublicProps (r:0 w:1) + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { - // Minimum execution time: 9_500 nanoseconds. - Weight::from_ref_time(9_800_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_020 nanoseconds. + Weight::from_ref_time(5_230_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - // Minimum execution time: 45_301 nanoseconds. - Weight::from_ref_time(55_586_580) - // Standard Error: 3_284 - .saturating_add(Weight::from_ref_time(131_584).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `12647` + // Minimum execution time: 27_161 nanoseconds. + Weight::from_parts(34_479_852, 12647) + // Standard Error: 1_670 + .saturating_add(Weight::from_ref_time(33_755).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - // Minimum execution time: 52_601 nanoseconds. - Weight::from_ref_time(54_790_133) - // Standard Error: 1_781 - .saturating_add(Weight::from_ref_time(187_548).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `580 + r * (22 ±0)` + // Estimated: `12647` + // Minimum execution time: 32_591 nanoseconds. + Weight::from_parts(33_734_030, 12647) + // Standard Error: 665 + .saturating_add(Weight::from_ref_time(75_086).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - // Minimum execution time: 28_301 nanoseconds. - Weight::from_ref_time(31_508_014) - // Standard Error: 1_665 - .saturating_add(Weight::from_ref_time(176_456).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_430 nanoseconds. + Weight::from_parts(23_916_113, 8946) + // Standard Error: 994 + .saturating_add(Weight::from_ref_time(84_138).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - // Minimum execution time: 28_600 nanoseconds. - Weight::from_ref_time(31_853_370) - // Standard Error: 1_639 - .saturating_add(Weight::from_ref_time(175_476).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_731 nanoseconds. + Weight::from_parts(25_242_743, 8946) + // Standard Error: 2_707 + .saturating_add(Weight::from_ref_time(69_945).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/altair/src/weights/pallet_fees.rs b/runtime/altair/src/weights/pallet_fees.rs index 3ed2c7e556..fb38bdfcc1 100644 --- a/runtime/altair/src/weights/pallet_fees.rs +++ b/runtime/altair/src/weights/pallet_fees.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_fees` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,10 +31,14 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_fees`. pub struct WeightInfo(PhantomData); impl pallet_fees::WeightInfo for WeightInfo { - // Storage: Fees FeeBalances (r:0 w:1) + /// Storage: Fees FeeBalances (r:0 w:1) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn set_fee() -> Weight { - // Minimum execution time: 23_701 nanoseconds. - Weight::from_ref_time(24_200_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_772 nanoseconds. + Weight::from_ref_time(12_122_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/altair/src/weights/pallet_identity.rs b/runtime/altair/src/weights/pallet_identity.rs index 5206c25eea..ff8b07f281 100644 --- a/runtime/altair/src/weights/pallet_identity.rs +++ b/runtime/altair/src/weights/pallet_identity.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_identity` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,209 +31,291 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_identity`. pub struct WeightInfo(PhantomData); impl pallet_identity::WeightInfo for WeightInfo { - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - // Minimum execution time: 30_100 nanoseconds. - Weight::from_ref_time(31_219_510) - // Standard Error: 3_408 - .saturating_add(Weight::from_ref_time(288_217).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `63 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 17_031 nanoseconds. + Weight::from_parts(17_889_114, 1636) + // Standard Error: 2_152 + .saturating_add(Weight::from_ref_time(109_021).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 66_001 nanoseconds. - Weight::from_ref_time(63_240_609) - // Standard Error: 11_781 - .saturating_add(Weight::from_ref_time(259_632).saturating_mul(r.into())) - // Standard Error: 2_298 - .saturating_add(Weight::from_ref_time(710_307).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `473 + r * (5 ±0)` + // Estimated: `10013` + // Minimum execution time: 39_805 nanoseconds. + Weight::from_parts(39_165_697, 10013) + // Standard Error: 3_056 + .saturating_add(Weight::from_ref_time(98_004).saturating_mul(r.into())) + // Standard Error: 596 + .saturating_add(Weight::from_ref_time(581_236).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:2 w:2) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - // Minimum execution time: 19_000 nanoseconds. - Weight::from_ref_time(49_726_587) - // Standard Error: 16_179 - .saturating_add(Weight::from_ref_time(4_705_185).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `15746 + s * (2589 ±0)` + // Minimum execution time: 12_915 nanoseconds. + Weight::from_parts(29_021_391, 15746) + // Standard Error: 4_226 + .saturating_add(Weight::from_ref_time(4_305_058).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:2) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - // Minimum execution time: 19_101 nanoseconds. - Weight::from_ref_time(49_327_525) - // Standard Error: 6_142 - .saturating_add(Weight::from_ref_time(2_014_257).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `225 + p * (32 ±0)` + // Estimated: `15746` + // Minimum execution time: 13_044 nanoseconds. + Weight::from_parts(28_122_528, 15746) + // Standard Error: 3_567 + .saturating_add(Weight::from_ref_time(1_777_685).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Minimum execution time: 98_401 nanoseconds. - Weight::from_ref_time(64_405_894) - // Standard Error: 12_003 - .saturating_add(Weight::from_ref_time(201_303).saturating_mul(r.into())) - // Standard Error: 2_344 - .saturating_add(Weight::from_ref_time(1_929_005).saturating_mul(s.into())) - // Standard Error: 2_344 - .saturating_add(Weight::from_ref_time(374_437).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `532 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `15746` + // Minimum execution time: 69_019 nanoseconds. + Weight::from_parts(37_349_290, 15746) + // Standard Error: 7_789 + .saturating_add(Weight::from_ref_time(153_869).saturating_mul(r.into())) + // Standard Error: 1_521 + .saturating_add(Weight::from_ref_time(1_771_139).saturating_mul(s.into())) + // Standard Error: 1_521 + .saturating_add(Weight::from_ref_time(324_417).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 67_502 nanoseconds. - Weight::from_ref_time(63_222_605) - // Standard Error: 19_765 - .saturating_add(Weight::from_ref_time(345_691).saturating_mul(r.into())) - // Standard Error: 3_856 - .saturating_add(Weight::from_ref_time(740_244).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `430 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 40_646 nanoseconds. + Weight::from_parts(38_275_682, 11649) + // Standard Error: 6_208 + .saturating_add(Weight::from_ref_time(186_005).saturating_mul(r.into())) + // Standard Error: 1_211 + .saturating_add(Weight::from_ref_time(613_632).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 61_801 nanoseconds. - Weight::from_ref_time(58_899_591) - // Standard Error: 13_849 - .saturating_add(Weight::from_ref_time(282_235).saturating_mul(r.into())) - // Standard Error: 2_702 - .saturating_add(Weight::from_ref_time(730_608).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `429 + x * (66 ±0)` + // Estimated: `10013` + // Minimum execution time: 36_969 nanoseconds. + Weight::from_parts(35_857_780, 10013) + // Standard Error: 5_620 + .saturating_add(Weight::from_ref_time(107_038).saturating_mul(r.into())) + // Standard Error: 1_096 + .saturating_add(Weight::from_ref_time(617_150).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - // Minimum execution time: 16_100 nanoseconds. - Weight::from_ref_time(16_927_845) - // Standard Error: 3_165 - .saturating_add(Weight::from_ref_time(223_307).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 10_760 nanoseconds. + Weight::from_parts(11_203_271, 1636) + // Standard Error: 1_330 + .saturating_add(Weight::from_ref_time(82_260).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - // Minimum execution time: 16_501 nanoseconds. - Weight::from_ref_time(17_229_587) - // Standard Error: 3_700 - .saturating_add(Weight::from_ref_time(223_672).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_819 nanoseconds. + Weight::from_parts(10_291_090, 1636) + // Standard Error: 992 + .saturating_add(Weight::from_ref_time(76_706).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - // Minimum execution time: 16_200 nanoseconds. - Weight::from_ref_time(16_997_141) - // Standard Error: 3_332 - .saturating_add(Weight::from_ref_time(208_112).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_598 nanoseconds. + Weight::from_parts(10_075_996, 1636) + // Standard Error: 1_127 + .saturating_add(Weight::from_ref_time(79_229).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 50_801 nanoseconds. - Weight::from_ref_time(47_934_148) - // Standard Error: 12_296 - .saturating_add(Weight::from_ref_time(287_214).saturating_mul(r.into())) - // Standard Error: 2_275 - .saturating_add(Weight::from_ref_time(1_191_494).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `508 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 30_888 nanoseconds. + Weight::from_parts(29_420_302, 11649) + // Standard Error: 6_074 + .saturating_add(Weight::from_ref_time(116_693).saturating_mul(r.into())) + // Standard Error: 1_123 + .saturating_add(Weight::from_ref_time(977_871).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Identity SuperOf (r:0 w:100) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Minimum execution time: 120_602 nanoseconds. - Weight::from_ref_time(82_899_809) - // Standard Error: 12_825 - .saturating_add(Weight::from_ref_time(297_314).saturating_mul(r.into())) - // Standard Error: 2_504 - .saturating_add(Weight::from_ref_time(1_952_069).saturating_mul(s.into())) - // Standard Error: 2_504 - .saturating_add(Weight::from_ref_time(381_751).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `892 + r * (15 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `20952` + // Minimum execution time: 91_260 nanoseconds. + Weight::from_parts(60_029_664, 20952) + // Standard Error: 7_967 + .saturating_add(Weight::from_ref_time(135_838).saturating_mul(r.into())) + // Standard Error: 1_555 + .saturating_add(Weight::from_ref_time(1_785_621).saturating_mul(s.into())) + // Standard Error: 1_555 + .saturating_add(Weight::from_ref_time(336_436).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - // Minimum execution time: 58_501 nanoseconds. - Weight::from_ref_time(67_665_041) - // Standard Error: 5_863 - .saturating_add(Weight::from_ref_time(179_265).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `506 + s * (36 ±0)` + // Estimated: `18335` + // Minimum execution time: 36_859 nanoseconds. + Weight::from_parts(41_681_260, 18335) + // Standard Error: 1_329 + .saturating_add(Weight::from_ref_time(77_486).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - // Minimum execution time: 25_101 nanoseconds. - Weight::from_ref_time(28_286_469) - // Standard Error: 3_105 - .saturating_add(Weight::from_ref_time(102_128).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `622 + s * (3 ±0)` + // Estimated: `12602` + // Minimum execution time: 17_703 nanoseconds. + Weight::from_parts(20_123_333, 12602) + // Standard Error: 717 + .saturating_add(Weight::from_ref_time(21_822).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - // Minimum execution time: 64_201 nanoseconds. - Weight::from_ref_time(69_029_350) - // Standard Error: 3_959 - .saturating_add(Weight::from_ref_time(175_648).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `701 + s * (35 ±0)` + // Estimated: `18335` + // Minimum execution time: 40_456 nanoseconds. + Weight::from_parts(43_753_641, 18335) + // Standard Error: 1_097 + .saturating_add(Weight::from_ref_time(57_485).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - // Minimum execution time: 44_501 nanoseconds. - Weight::from_ref_time(49_905_502) - // Standard Error: 4_234 - .saturating_add(Weight::from_ref_time(160_972).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `627 + s * (37 ±0)` + // Estimated: `8322` + // Minimum execution time: 27_120 nanoseconds. + Weight::from_parts(29_260_115, 8322) + // Standard Error: 813 + .saturating_add(Weight::from_ref_time(68_203).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/altair/src/weights/pallet_interest_accrual.rs b/runtime/altair/src/weights/pallet_interest_accrual.rs index 327453e6fb..a4826c8df5 100644 --- a/runtime/altair/src/weights/pallet_interest_accrual.rs +++ b/runtime/altair/src/weights/pallet_interest_accrual.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_interest_accrual` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -32,9 +33,12 @@ pub struct WeightInfo(PhantomData); impl pallet_interest_accrual::WeightInfo for WeightInfo { /// The range of component `n` is `[1, 25]`. fn calculate_accumulated_rate(n: u32, ) -> Weight { - // Minimum execution time: 700 nanoseconds. - Weight::from_ref_time(800_000) - // Standard Error: 1_781 - .saturating_add(Weight::from_ref_time(784_636).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 692 nanoseconds. + Weight::from_ref_time(278_896) + // Standard Error: 398 + .saturating_add(Weight::from_ref_time(639_336).saturating_mul(n.into())) } } diff --git a/runtime/altair/src/weights/pallet_keystore.rs b/runtime/altair/src/weights/pallet_keystore.rs index 7e2d135e95..f7f7615edb 100644 --- a/runtime/altair/src/weights/pallet_keystore.rs +++ b/runtime/altair/src/weights/pallet_keystore.rs @@ -2,12 +2,13 @@ //! Autogenerated weights for `pallet_keystore` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: -// target/release/altair +// target/release/centrifuge-chain // benchmark // pallet // --chain=altair-dev @@ -30,35 +31,52 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_keystore`. pub struct WeightInfo(PhantomData); impl pallet_keystore::WeightInfo for WeightInfo { - // Storage: Keystore KeyDeposit (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Keystore Keys (r:1 w:1) - // Storage: Keystore LastKeyByPurpose (r:0 w:1) + /// Storage: Keystore KeyDeposit (r:1 w:0) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) + /// Storage: Keystore LastKeyByPurpose (r:0 w:1) + /// Proof: Keystore LastKeyByPurpose (max_values: None, max_size: Some(97), added: 2572, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn add_keys(n: u32, ) -> Weight { - // Minimum execution time: 46_877 nanoseconds. - Weight::from_ref_time(27_236_613) - // Standard Error: 12_118 - .saturating_add(Weight::from_ref_time(21_832_427).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `3114 + n * (2595 ±0)` + // Minimum execution time: 38_382 nanoseconds. + Weight::from_parts(17_487_197, 3114) + // Standard Error: 10_244 + .saturating_add(Weight::from_ref_time(22_274_269).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - // Storage: Keystore Keys (r:1 w:1) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn revoke_keys(n: u32, ) -> Weight { - // Minimum execution time: 30_968 nanoseconds. - Weight::from_ref_time(20_261_880) - // Standard Error: 13_719 - .saturating_add(Weight::from_ref_time(12_291_737).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `148 + n * (75 ±0)` + // Estimated: `0 + n * (2595 ±0)` + // Minimum execution time: 22_022 nanoseconds. + Weight::from_ref_time(10_913_012) + // Standard Error: 12_462 + .saturating_add(Weight::from_ref_time(12_387_370).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - // Storage: Keystore KeyDeposit (r:0 w:1) + /// Storage: Keystore KeyDeposit (r:0 w:1) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_deposit() -> Weight { - // Minimum execution time: 20_428 nanoseconds. - Weight::from_ref_time(21_119_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_301 nanoseconds. + Weight::from_ref_time(12_023_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/altair/src/weights/pallet_loans.rs b/runtime/altair/src/weights/pallet_loans.rs index b750f2833c..139a064ce9 100644 --- a/runtime/altair/src/weights/pallet_loans.rs +++ b/runtime/altair/src/weights/pallet_loans.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_loans` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,146 +31,266 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_loans`. pub struct WeightInfo(PhantomData); impl pallet_loans::WeightInfo for WeightInfo { - // Storage: Permissions Permission (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Uniques Class (r:1 w:0) - // Storage: Loans LastLoanId (r:1 w:1) - // Storage: Loans CreatedLoan (r:0 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Loans LastLoanId (r:1 w:1) + /// Proof: Loans LastLoanId (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Loans CreatedLoan (r:0 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 105_202 nanoseconds. - Weight::from_ref_time(106_302_000) + // Proof Size summary in bytes: + // Measured: `1167` + // Estimated: `14271` + // Minimum execution time: 78_207 nanoseconds. + Weight::from_parts(79_158_000, 14271) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: Loans CreatedLoan (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:0) - /// The range of component `n` is `[1, 299]`. + /// Storage: Loans CreatedLoan (r:1 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn borrow(n: u32, ) -> Weight { - // Minimum execution time: 196_903 nanoseconds. - Weight::from_ref_time(195_042_460) - // Standard Error: 6_848 - .saturating_add(Weight::from_ref_time(1_026_277).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `12904 + n * (340 ±0)` + // Estimated: `136131` + // Minimum execution time: 171_220 nanoseconds. + Weight::from_parts(175_114_994, 136131) + // Standard Error: 38_769 + .saturating_add(Weight::from_ref_time(739_775).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:0) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:0) - /// The range of component `n` is `[1, 299]`. - fn repay(n: u32, ) -> Weight { - // Minimum execution time: 166_603 nanoseconds. - Weight::from_ref_time(162_750_552) - // Standard Error: 6_810 - .saturating_add(Weight::from_ref_time(1_031_483).saturating_mul(n.into())) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn repay(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12960 + n * (340 ±0)` + // Estimated: `133428` + // Minimum execution time: 147_757 nanoseconds. + Weight::from_parts(154_119_300, 133428) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Loans WriteOffPolicy (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - /// The range of component `n` is `[1, 299]`. + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn write_off(n: u32, ) -> Weight { - // Minimum execution time: 263_205 nanoseconds. - Weight::from_ref_time(256_972_263) - // Standard Error: 6_444 - .saturating_add(Weight::from_ref_time(1_043_150).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `15968 + n * (340 ±0)` + // Estimated: `129930` + // Minimum execution time: 237_785 nanoseconds. + Weight::from_parts(241_650_438, 129930) + // Standard Error: 42_611 + .saturating_add(Weight::from_ref_time(858_955).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Loans WriteOffPolicy (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - /// The range of component `n` is `[1, 299]`. + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn admin_write_off(n: u32, ) -> Weight { - // Minimum execution time: 283_205 nanoseconds. - Weight::from_ref_time(276_944_904) - // Standard Error: 7_164 - .saturating_add(Weight::from_ref_time(1_043_195).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `16219 + n * (340 ±0)` + // Estimated: `132633` + // Minimum execution time: 258_483 nanoseconds. + Weight::from_parts(261_257_664, 132633) + // Standard Error: 21_691 + .saturating_add(Weight::from_ref_time(578_728).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Loans CreatedLoan (r:1 w:0) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Loans ClosedLoan (r:0 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) - /// The range of component `n` is `[1, 299]`. + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn propose_loan_mutation(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `904 + n * (316 ±0)` + // Estimated: `103507` + // Minimum execution time: 45_365 nanoseconds. + Weight::from_parts(48_365_702, 103507) + // Standard Error: 24_016 + .saturating_add(Weight::from_ref_time(298_719).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn apply_loan_mutation(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12305 + n * (340 ±0)` + // Estimated: `133276` + // Minimum execution time: 92_102 nanoseconds. + Weight::from_parts(94_995_468, 133276) + // Standard Error: 23_203 + .saturating_add(Weight::from_ref_time(561_602).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Loans CreatedLoan (r:1 w:0) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Loans ClosedLoan (r:0 w:1) + /// Proof: Loans ClosedLoan (max_values: None, max_size: Some(264), added: 2739, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn close(n: u32, ) -> Weight { - // Minimum execution time: 118_402 nanoseconds. - Weight::from_ref_time(112_255_619) - // Standard Error: 6_961 - .saturating_add(Weight::from_ref_time(991_554).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `12067 + n * (349 ±0)` + // Estimated: `119571` + // Minimum execution time: 96_040 nanoseconds. + Weight::from_parts(97_557_750, 119571) + // Standard Error: 26_998 + .saturating_add(Weight::from_ref_time(1_195_533).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Loans WriteOffPolicy (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) fn propose_write_off_policy() -> Weight { - // Minimum execution time: 108_502 nanoseconds. - Weight::from_ref_time(111_501_000) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `512` + // Estimated: `6494` + // Minimum execution time: 87_684 nanoseconds. + Weight::from_parts(89_468_000, 6494) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - fn propose_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - - fn apply_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Loans WriteOffPolicy (r:0 w:1) + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) fn apply_write_off_policy() -> Weight { - // Minimum execution time: 108_502 nanoseconds. - Weight::from_ref_time(111_501_000) + // Proof Size summary in bytes: + // Measured: `4950` + // Estimated: `10947` + // Minimum execution time: 91_411 nanoseconds. + Weight::from_parts(92_393_000, 10947) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:0) - // Storage: Loans ActiveLoans (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - /// The range of component `n` is `[1, 300]`. + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(10802), added: 11297, mode: MaxEncodedLen) + /// Storage: PriceCollector Collection (r:1 w:0) + /// Proof: PriceCollector Collection (max_values: None, max_size: Some(11126), added: 13601, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(97826), added: 100301, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:0 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. fn update_portfolio_valuation(n: u32, ) -> Weight { - // Minimum execution time: 85_902 nanoseconds. - Weight::from_ref_time(84_278_313) - // Standard Error: 3_513 - .saturating_add(Weight::from_ref_time(11_474_528).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `11726 + n * (316 ±0)` + // Estimated: `128990` + // Minimum execution time: 77_354 nanoseconds. + Weight::from_parts(72_309_599, 128990) + // Standard Error: 23_156 + .saturating_add(Weight::from_ref_time(9_481_609).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_migration_manager.rs b/runtime/altair/src/weights/pallet_migration_manager.rs index b7f4cb3576..e253fbef22 100644 --- a/runtime/altair/src/weights/pallet_migration_manager.rs +++ b/runtime/altair/src/weights/pallet_migration_manager.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_migration_manager` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,55 +31,81 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_migration_manager`. pub struct WeightInfo(PhantomData); impl pallet_migration_manager::WeightInfo for WeightInfo { - // Storage: Migration Status (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn finalize() -> Weight { - // Minimum execution time: 29_800 nanoseconds. - Weight::from_ref_time(30_500_000) + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `496` + // Minimum execution time: 17_924 nanoseconds. + Weight::from_parts(18_604_000, 496) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Migration Status (r:1 w:1) - // Storage: System Account (r:0 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: System Account (r:0 w:100) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 100]`. fn migrate_system_account(n: u32, ) -> Weight { - // Minimum execution time: 32_000 nanoseconds. - Weight::from_ref_time(31_809_116) - // Standard Error: 11_304 - .saturating_add(Weight::from_ref_time(1_293_803).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 19_146 nanoseconds. + Weight::from_parts(19_178_557, 496) + // Standard Error: 1_752 + .saturating_add(Weight::from_ref_time(1_065_371).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } - // Storage: Migration Status (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn migrate_balances_issuance() -> Weight { - // Minimum execution time: 35_801 nanoseconds. - Weight::from_ref_time(47_501_000) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 19_176 nanoseconds. + Weight::from_parts(19_888_000, 496) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Migration Status (r:1 w:1) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:10 w:10) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:10 w:10) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:10 w:10) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn migrate_vesting_vesting(n: u32, ) -> Weight { - // Minimum execution time: 121_802 nanoseconds. - Weight::from_ref_time(98_158_299) - // Standard Error: 99_624 - .saturating_add(Weight::from_ref_time(38_488_345).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `363 + n * (461 ±0)` + // Estimated: `496 + n * (9909 ±0)` + // Minimum execution time: 66_244 nanoseconds. + Weight::from_parts(37_966_574, 496) + // Standard Error: 40_319 + .saturating_add(Weight::from_ref_time(34_296_158).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(9909).saturating_mul(n.into())) } - // Storage: Migration Status (r:1 w:1) - // Storage: Proxy Proxies (r:0 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Proxy Proxies (r:0 w:10) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn migrate_proxy_proxies(n: u32, ) -> Weight { - // Minimum execution time: 71_001 nanoseconds. - Weight::from_ref_time(71_833_963) - // Standard Error: 67_845 - .saturating_add(Weight::from_ref_time(9_368_247).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 33_022 nanoseconds. + Weight::from_parts(27_431_566, 496) + // Standard Error: 12_038 + .saturating_add(Weight::from_ref_time(7_410_240).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) diff --git a/runtime/altair/src/weights/pallet_multisig.rs b/runtime/altair/src/weights/pallet_multisig.rs index da50066094..8eda9929d5 100644 --- a/runtime/altair/src/weights/pallet_multisig.rs +++ b/runtime/altair/src/weights/pallet_multisig.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -32,80 +33,106 @@ pub struct WeightInfo(PhantomData); impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { - // Minimum execution time: 28_100 nanoseconds. - Weight::from_ref_time(29_625_429) - // Standard Error: 12 - .saturating_add(Weight::from_ref_time(655).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 17_252 nanoseconds. + Weight::from_ref_time(18_173_988) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(501).saturating_mul(z.into())) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 81_601 nanoseconds. - Weight::from_ref_time(65_868_985) - // Standard Error: 2_835 - .saturating_add(Weight::from_ref_time(184_587).saturating_mul(s.into())) - // Standard Error: 27 - .saturating_add(Weight::from_ref_time(2_067).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 50_234 nanoseconds. + Weight::from_parts(42_484_194, 5821) + // Standard Error: 789 + .saturating_add(Weight::from_ref_time(90_468).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_740).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 61_301 nanoseconds. - Weight::from_ref_time(61_010_654) - // Standard Error: 11_750 - .saturating_add(Weight::from_ref_time(25_251).saturating_mul(s.into())) - // Standard Error: 115 - .saturating_add(Weight::from_ref_time(1_985).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 35_296 nanoseconds. + Weight::from_parts(28_047_907, 5821) + // Standard Error: 580 + .saturating_add(Weight::from_ref_time(84_689).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_729).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 83_902 nanoseconds. - Weight::from_ref_time(66_661_291) - // Standard Error: 2_643 - .saturating_add(Weight::from_ref_time(215_731).saturating_mul(s.into())) - // Standard Error: 25 - .saturating_add(Weight::from_ref_time(2_183).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `550 + s * (33 ±0)` + // Estimated: `8424` + // Minimum execution time: 56_997 nanoseconds. + Weight::from_parts(48_103_260, 8424) + // Standard Error: 3_304 + .saturating_add(Weight::from_ref_time(115_869).saturating_mul(s.into())) + // Standard Error: 32 + .saturating_add(Weight::from_ref_time(1_667).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // Minimum execution time: 59_001 nanoseconds. - Weight::from_ref_time(62_867_114) - // Standard Error: 2_997 - .saturating_add(Weight::from_ref_time(201_518).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 38_833 nanoseconds. + Weight::from_parts(40_316_161, 5821) + // Standard Error: 973 + .saturating_add(Weight::from_ref_time(93_173).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // Minimum execution time: 40_700 nanoseconds. - Weight::from_ref_time(43_041_898) - // Standard Error: 2_568 - .saturating_add(Weight::from_ref_time(190_673).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 25_217 nanoseconds. + Weight::from_parts(26_025_594, 5821) + // Standard Error: 764 + .saturating_add(Weight::from_ref_time(81_598).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // Minimum execution time: 57_701 nanoseconds. - Weight::from_ref_time(61_137_098) - // Standard Error: 3_915 - .saturating_add(Weight::from_ref_time(187_762).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `616 + s * (1 ±0)` + // Estimated: `5821` + // Minimum execution time: 39_705 nanoseconds. + Weight::from_parts(40_947_167, 5821) + // Standard Error: 853 + .saturating_add(Weight::from_ref_time(87_849).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_nft_sales.rs b/runtime/altair/src/weights/pallet_nft_sales.rs index 7091c759fc..820ba54bf0 100644 --- a/runtime/altair/src/weights/pallet_nft_sales.rs +++ b/runtime/altair/src/weights/pallet_nft_sales.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_nft_sales` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,41 +31,70 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_nft_sales`. pub struct WeightInfo(PhantomData); impl pallet_nft_sales::WeightInfo for WeightInfo { - // Storage: Uniques Asset (r:1 w:1) - // Storage: NftSales Sales (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) - // Storage: NftSales NftsBySeller (r:0 w:1) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: NftSales Sales (r:1 w:1) + /// Proof: NftSales Sales (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: NftSales NftsBySeller (r:0 w:1) + /// Proof: NftSales NftsBySeller (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn add() -> Weight { - // Minimum execution time: 78_302 nanoseconds. - Weight::from_ref_time(79_302_000) + // Proof Size summary in bytes: + // Measured: `688` + // Estimated: `7874` + // Minimum execution time: 58_489 nanoseconds. + Weight::from_parts(60_163_000, 7874) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: NftSales Sales (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:1) - // Storage: Uniques ItemPriceOf (r:0 w:1) - // Storage: NftSales NftsBySeller (r:0 w:1) + /// Storage: NftSales Sales (r:1 w:1) + /// Proof: NftSales Sales (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: NftSales NftsBySeller (r:0 w:1) + /// Proof: NftSales NftsBySeller (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn remove() -> Weight { - // Minimum execution time: 77_401 nanoseconds. - Weight::from_ref_time(78_302_000) + // Proof Size summary in bytes: + // Measured: `856` + // Estimated: `7874` + // Minimum execution time: 57_829 nanoseconds. + Weight::from_parts(58_450_000, 7874) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: NftSales Sales (r:1 w:1) - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) - // Storage: NftSales NftsBySeller (r:0 w:1) + /// Storage: NftSales Sales (r:1 w:1) + /// Proof: NftSales Sales (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: NftSales NftsBySeller (r:0 w:1) + /// Proof: NftSales NftsBySeller (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn buy() -> Weight { - // Minimum execution time: 126_202 nanoseconds. - Weight::from_ref_time(127_402_000) + // Proof Size summary in bytes: + // Measured: `1377` + // Estimated: `15685` + // Minimum execution time: 100_508 nanoseconds. + Weight::from_parts(102_342_000, 15685) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(9)) } diff --git a/runtime/altair/src/weights/pallet_permissions.rs b/runtime/altair/src/weights/pallet_permissions.rs index 0bd0d6dab4..35e8ac9e2f 100644 --- a/runtime/altair/src/weights/pallet_permissions.rs +++ b/runtime/altair/src/weights/pallet_permissions.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_permissions` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,49 +31,77 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_permissions`. pub struct WeightInfo(PhantomData); impl pallet_permissions::WeightInfo for WeightInfo { - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn add_as_admin() -> Weight { - // Minimum execution time: 35_001 nanoseconds. - Weight::from_ref_time(35_801_000) + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `5224` + // Minimum execution time: 20_559 nanoseconds. + Weight::from_parts(21_290_000, 5224) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn add_as_editor() -> Weight { - // Minimum execution time: 43_800 nanoseconds. - Weight::from_ref_time(44_801_000) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `7927` + // Minimum execution time: 27_972 nanoseconds. + Weight::from_parts(28_794_000, 7927) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn remove_as_admin() -> Weight { - // Minimum execution time: 38_401 nanoseconds. - Weight::from_ref_time(39_400_000) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `5224` + // Minimum execution time: 23_874 nanoseconds. + Weight::from_parts(24_346_000, 5224) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn remove_as_editor() -> Weight { - // Minimum execution time: 46_600 nanoseconds. - Weight::from_ref_time(47_701_000) + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `7927` + // Minimum execution time: 30_427 nanoseconds. + Weight::from_parts(31_189_000, 7927) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn purge() -> Weight { - // Minimum execution time: 35_201 nanoseconds. - Weight::from_ref_time(35_801_000) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 21_039 nanoseconds. + Weight::from_parts(21_511_000, 2703) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn admin_purge() -> Weight { - // Minimum execution time: 54_901 nanoseconds. - Weight::from_ref_time(55_801_000) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 21_600 nanoseconds. + Weight::from_parts(22_132_000, 2703) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_pool_registry.rs b/runtime/altair/src/weights/pallet_pool_registry.rs index 8bd1f5433e..53250bd6cc 100644 --- a/runtime/altair/src/weights/pallet_pool_registry.rs +++ b/runtime/altair/src/weights/pallet_pool_registry.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_pool_registry` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,82 +31,132 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_pool_registry`. pub struct WeightInfo(PhantomData); impl pallet_pool_registry::WeightInfo for WeightInfo { - // Storage: PoolRegistry Pools (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem AccountDeposit (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) - // Storage: PoolSystem PoolDeposit (r:0 w:1) + /// Storage: PoolRegistry Pools (r:1 w:1) + /// Proof: PoolRegistry Pools (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:6 w:5) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: PoolSystem AccountDeposit (r:1 w:1) + /// Proof: PoolSystem AccountDeposit (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: PoolSystem PoolDeposit (r:0 w:1) + /// Proof: PoolSystem PoolDeposit (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn register(n: u32, ) -> Weight { - // Minimum execution time: 102_901 nanoseconds. - Weight::from_ref_time(87_373_356) - // Standard Error: 29_215 - .saturating_add(Weight::from_ref_time(17_496_106).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `470` + // Estimated: `16999 + n * (2475 ±0)` + // Minimum execution time: 136_295 nanoseconds. + Weight::from_parts(123_536_959, 16999) + // Standard Error: 37_550 + .saturating_add(Weight::from_ref_time(15_869_190).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2475).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn update_no_execution(n: u32, ) -> Weight { - // Minimum execution time: 70_802 nanoseconds. - Weight::from_ref_time(70_227_157) - // Standard Error: 22_279 - .saturating_add(Weight::from_ref_time(2_744_247).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `786 + n * (133 ±0)` + // Estimated: `9739 + n * (2531 ±0)` + // Minimum execution time: 48_901 nanoseconds. + Weight::from_parts(47_736_301, 9739) + // Standard Error: 14_248 + .saturating_add(Weight::from_ref_time(2_463_740).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2531).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) - // Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn update_and_execute(n: u32, ) -> Weight { - // Minimum execution time: 103_201 nanoseconds. - Weight::from_ref_time(96_453_204) - // Standard Error: 34_184 - .saturating_add(Weight::from_ref_time(8_717_524).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `877 + n * (167 ±0)` + // Estimated: `15566 + n * (2699 ±0)` + // Minimum execution time: 82_383 nanoseconds. + Weight::from_parts(77_237_572, 15566) + // Standard Error: 31_387 + .saturating_add(Weight::from_ref_time(8_381_428).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2699).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem ScheduledUpdate (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:1 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[1, 5]`. fn execute_update(n: u32, ) -> Weight { - // Minimum execution time: 93_502 nanoseconds. - Weight::from_ref_time(86_558_286) - // Standard Error: 88_417 - .saturating_add(Weight::from_ref_time(9_187_996).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `899 + n * (194 ±0)` + // Estimated: `16379 + n * (2725 ±0)` + // Minimum execution time: 72_565 nanoseconds. + Weight::from_parts(66_564_729, 16379) + // Standard Error: 31_209 + .saturating_add(Weight::from_ref_time(8_433_874).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2725).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolRegistry PoolMetadata (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolRegistry PoolMetadata (r:0 w:1) + /// Proof: PoolRegistry PoolMetadata (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) /// The range of component `n` is `[0, 46]`. fn set_metadata(n: u32, ) -> Weight { - // Minimum execution time: 37_900 nanoseconds. - Weight::from_ref_time(39_268_285) - // Standard Error: 1_120 - .saturating_add(Weight::from_ref_time(16_046).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 22_201 nanoseconds. + Weight::from_parts(23_327_207, 2703) + // Standard Error: 818 + .saturating_add(Weight::from_ref_time(684).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_pool_system.rs b/runtime/altair/src/weights/pallet_pool_system.rs index b54c05c43a..b4a2c6cb1c 100644 --- a/runtime/altair/src/weights/pallet_pool_system.rs +++ b/runtime/altair/src/weights/pallet_pool_system.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_pool_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,121 +31,201 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_pool_system`. pub struct WeightInfo(PhantomData); impl pallet_pool_system::WeightInfo for WeightInfo { - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) fn set_max_reserve() -> Weight { - // Minimum execution time: 46_501 nanoseconds. - Weight::from_ref_time(47_201_000) + // Proof Size summary in bytes: + // Measured: `657` + // Estimated: `5991` + // Minimum execution time: 28_563 nanoseconds. + Weight::from_parts(29_435_000, 5991) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:5 w:0) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_orders(n: u32, ) -> Weight { - // Minimum execution time: 151_402 nanoseconds. - Weight::from_ref_time(69_360_773) - // Standard Error: 73_171 - .saturating_add(Weight::from_ref_time(84_670_734).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `775 + n * (133 ±0)` + // Estimated: `16761 + n * (20298 ±0)` + // Minimum execution time: 119_753 nanoseconds. + Weight::from_parts(49_735_771, 16761) + // Standard Error: 37_600 + .saturating_add(Weight::from_ref_time(72_455_815).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_execution(n: u32, ) -> Weight { - // Minimum execution time: 110_502 nanoseconds. - Weight::from_ref_time(77_020_823) - // Standard Error: 186_595 - .saturating_add(Weight::from_ref_time(35_804_170).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `941 + n * (133 ±0)` + // Estimated: `16761 + n * (17694 ±0)` + // Minimum execution time: 82_735 nanoseconds. + Weight::from_parts(54_423_512, 16761) + // Standard Error: 26_925 + .saturating_add(Weight::from_ref_time(30_656_775).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17694).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(7250), added: 9725, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_execute(n: u32, ) -> Weight { - // Minimum execution time: 252_404 nanoseconds. - Weight::from_ref_time(169_648_258) - // Standard Error: 85_986 - .saturating_add(Weight::from_ref_time(86_616_563).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `1459 + n * (133 ±0)` + // Estimated: `27175 + n * (20298 ±0)` + // Minimum execution time: 205_214 nanoseconds. + Weight::from_parts(134_682_304, 27175) + // Standard Error: 53_988 + .saturating_add(Weight::from_ref_time(74_087_637).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(7)) .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:0) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn submit_solution(n: u32, ) -> Weight { - // Minimum execution time: 48_901 nanoseconds. - Weight::from_ref_time(48_532_281) - // Standard Error: 225_822 - .saturating_add(Weight::from_ref_time(2_876_995).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `493 + n * (249 ±0)` + // Estimated: `6533` + // Minimum execution time: 30_588 nanoseconds. + Weight::from_parts(30_647_710, 6533) + // Standard Error: 9_293 + .saturating_add(Weight::from_ref_time(967_481).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:0) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:0) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn execute_epoch(n: u32, ) -> Weight { - // Minimum execution time: 216_803 nanoseconds. - Weight::from_ref_time(157_690_567) - // Standard Error: 89_843 - .saturating_add(Weight::from_ref_time(63_588_528).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `1470 + n * (605 ±0)` + // Estimated: `19974 + n * (17774 ±0)` + // Minimum execution time: 172_953 nanoseconds. + Weight::from_parts(122_771_002, 19974) + // Standard Error: 45_329 + .saturating_add(Weight::from_ref_time(53_563_882).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(8)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(n.into())) } } diff --git a/runtime/altair/src/weights/pallet_preimage.rs b/runtime/altair/src/weights/pallet_preimage.rs index 49a447dc42..2114031c4e 100644 --- a/runtime/altair/src/weights/pallet_preimage.rs +++ b/runtime/altair/src/weights/pallet_preimage.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_preimage` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,102 +31,156 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_preimage`. pub struct WeightInfo(PhantomData); impl pallet_preimage::WeightInfo for WeightInfo { - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - // Minimum execution time: 52_601 nanoseconds. - Weight::from_ref_time(10_335_004) - // Standard Error: 16 - .saturating_add(Weight::from_ref_time(2_921).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `209` + // Estimated: `2566` + // Minimum execution time: 36_158 nanoseconds. + Weight::from_parts(173_933_357, 2566) + // Standard Error: 14 + .saturating_add(Weight::from_ref_time(2_242).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - // Minimum execution time: 36_501 nanoseconds. - Weight::from_ref_time(36_901_000) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(3_061).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 22_923 nanoseconds. + Weight::from_parts(23_344_000, 2566) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(2_493).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Minimum execution time: 34_001 nanoseconds. - Weight::from_ref_time(34_601_000) - // Standard Error: 8 - .saturating_add(Weight::from_ref_time(3_097).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 21_730 nanoseconds. + Weight::from_parts(5_139_031, 2566) + // Standard Error: 9 + .saturating_add(Weight::from_ref_time(2_448).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { - // Minimum execution time: 97_901 nanoseconds. - Weight::from_ref_time(105_702_000) + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `2566` + // Minimum execution time: 41_247 nanoseconds. + Weight::from_parts(44_253_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_no_deposit_preimage() -> Weight { - // Minimum execution time: 74_901 nanoseconds. - Weight::from_ref_time(81_101_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 26_930 nanoseconds. + Weight::from_parts(29_566_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { - // Minimum execution time: 74_201 nanoseconds. - Weight::from_ref_time(77_801_000) + // Proof Size summary in bytes: + // Measured: `254` + // Estimated: `2566` + // Minimum execution time: 23_845 nanoseconds. + Weight::from_parts(25_247_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_no_deposit_preimage() -> Weight { - // Minimum execution time: 43_100 nanoseconds. - Weight::from_ref_time(48_701_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 14_247 nanoseconds. + Weight::from_parts(15_258_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_unnoted_preimage() -> Weight { - // Minimum execution time: 38_001 nanoseconds. - Weight::from_ref_time(39_500_000) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `2566` + // Minimum execution time: 20_187 nanoseconds. + Weight::from_parts(21_811_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_requested_preimage() -> Weight { - // Minimum execution time: 17_500 nanoseconds. - Weight::from_ref_time(18_201_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_003 nanoseconds. + Weight::from_parts(12_754_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unrequest_preimage() -> Weight { - // Minimum execution time: 72_701 nanoseconds. - Weight::from_ref_time(76_501_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 24_816 nanoseconds. + Weight::from_parts(27_863_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_unnoted_preimage() -> Weight { - // Minimum execution time: 17_300 nanoseconds. - Weight::from_ref_time(17_800_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_063 nanoseconds. + Weight::from_parts(12_514_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_multi_referenced_preimage() -> Weight { - // Minimum execution time: 17_000 nanoseconds. - Weight::from_ref_time(17_600_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_143 nanoseconds. + Weight::from_parts(12_653_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_proxy.rs b/runtime/altair/src/weights/pallet_proxy.rs index c4c3e9784b..4563f118c3 100644 --- a/runtime/altair/src/weights/pallet_proxy.rs +++ b/runtime/altair/src/weights/pallet_proxy.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,119 +31,164 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - // Storage: Proxy Proxies (r:1 w:0) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - // Minimum execution time: 36_601 nanoseconds. - Weight::from_ref_time(38_097_445) - // Standard Error: 4_112 - .saturating_add(Weight::from_ref_time(83_131).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 23_084 nanoseconds. + Weight::from_parts(24_079_348, 3716) + // Standard Error: 1_508 + .saturating_add(Weight::from_ref_time(31_652).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 68_901 nanoseconds. - Weight::from_ref_time(69_577_739) - // Standard Error: 6_187 - .saturating_add(Weight::from_ref_time(268_139).saturating_mul(a.into())) - // Standard Error: 6_392 - .saturating_add(Weight::from_ref_time(66_674).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `650 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 47_830 nanoseconds. + Weight::from_parts(48_495_120, 11027) + // Standard Error: 2_359 + .saturating_add(Weight::from_ref_time(179_591).saturating_mul(a.into())) + // Standard Error: 2_437 + .saturating_add(Weight::from_ref_time(37_108).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, _p: u32, ) -> Weight { - // Minimum execution time: 47_100 nanoseconds. - Weight::from_ref_time(55_599_984) - // Standard Error: 36_928 - .saturating_add(Weight::from_ref_time(288_232).saturating_mul(a.into())) + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 29_254 nanoseconds. + Weight::from_parts(30_495_295, 7311) + // Standard Error: 1_912 + .saturating_add(Weight::from_ref_time(172_029).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 47_401 nanoseconds. - Weight::from_ref_time(50_445_551) - // Standard Error: 16_253 - .saturating_add(Weight::from_ref_time(208_262).saturating_mul(a.into())) - // Standard Error: 16_793 - .saturating_add(Weight::from_ref_time(37_534).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 28_954 nanoseconds. + Weight::from_parts(29_926_712, 7311) + // Standard Error: 1_848 + .saturating_add(Weight::from_ref_time(179_134).saturating_mul(a.into())) + // Standard Error: 1_909 + .saturating_add(Weight::from_ref_time(8_491).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 61_501 nanoseconds. - Weight::from_ref_time(64_017_053) - // Standard Error: 9_027 - .saturating_add(Weight::from_ref_time(234_758).saturating_mul(a.into())) - // Standard Error: 9_327 - .saturating_add(Weight::from_ref_time(48_603).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `582 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 40_606 nanoseconds. + Weight::from_parts(42_333_976, 11027) + // Standard Error: 2_429 + .saturating_add(Weight::from_ref_time(166_395).saturating_mul(a.into())) + // Standard Error: 2_509 + .saturating_add(Weight::from_ref_time(34_922).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - // Minimum execution time: 51_301 nanoseconds. - Weight::from_ref_time(52_862_935) - // Standard Error: 2_216 - .saturating_add(Weight::from_ref_time(113_180).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_569 nanoseconds. + Weight::from_parts(32_505_252, 3716) + // Standard Error: 1_510 + .saturating_add(Weight::from_ref_time(49_327).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - // Minimum execution time: 51_201 nanoseconds. - Weight::from_ref_time(52_562_098) - // Standard Error: 10_087 - .saturating_add(Weight::from_ref_time(178_106).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_209 nanoseconds. + Weight::from_parts(32_426_501, 3716) + // Standard Error: 1_723 + .saturating_add(Weight::from_ref_time(64_741).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - // Minimum execution time: 44_601 nanoseconds. - Weight::from_ref_time(45_791_356) - // Standard Error: 14_252 - .saturating_add(Weight::from_ref_time(142_181).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 24_957 nanoseconds. + Weight::from_parts(26_080_289, 3716) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(43_546).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - // Minimum execution time: 58_901 nanoseconds. - Weight::from_ref_time(60_232_712) - // Standard Error: 2_229 - .saturating_add(Weight::from_ref_time(50_199).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `239` + // Estimated: `3716` + // Minimum execution time: 34_064 nanoseconds. + Weight::from_parts(35_053_014, 3716) + // Standard Error: 1_756 + .saturating_add(Weight::from_ref_time(25_681).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - // Minimum execution time: 47_101 nanoseconds. - Weight::from_ref_time(48_266_664) - // Standard Error: 11_304 - .saturating_add(Weight::from_ref_time(117_324).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `296 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 26_180 nanoseconds. + Weight::from_parts(27_163_347, 3716) + // Standard Error: 1_868 + .saturating_add(Weight::from_ref_time(44_743).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/altair/src/weights/pallet_restricted_tokens.rs b/runtime/altair/src/weights/pallet_restricted_tokens.rs index 167932a18e..d119269241 100644 --- a/runtime/altair/src/weights/pallet_restricted_tokens.rs +++ b/runtime/altair/src/weights/pallet_restricted_tokens.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_restricted_tokens` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,79 +31,125 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_restricted_tokens`. pub struct WeightInfo(PhantomData); impl pallet_restricted_tokens::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_native() -> Weight { - // Minimum execution time: 70_401 nanoseconds. - Weight::from_ref_time(71_402_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 52_358 nanoseconds. + Weight::from_parts(53_380_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_other() -> Weight { - // Minimum execution time: 76_601 nanoseconds. - Weight::from_ref_time(77_701_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 54_071 nanoseconds. + Weight::from_parts(56_185_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_native() -> Weight { - // Minimum execution time: 63_801 nanoseconds. - Weight::from_ref_time(64_501_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 45_955 nanoseconds. + Weight::from_parts(46_907_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_other() -> Weight { - // Minimum execution time: 71_001 nanoseconds. - Weight::from_ref_time(72_301_000) + // Proof Size summary in bytes: + // Measured: `438` + // Estimated: `7811` + // Minimum execution time: 51_046 nanoseconds. + Weight::from_parts(52_187_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_native() -> Weight { - // Minimum execution time: 74_201 nanoseconds. - Weight::from_ref_time(75_301_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 55_825 nanoseconds. + Weight::from_parts(56_536_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_other() -> Weight { - // Minimum execution time: 80_401 nanoseconds. - Weight::from_ref_time(81_101_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 58_790 nanoseconds. + Weight::from_parts(59_872_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_native() -> Weight { - // Minimum execution time: 70_401 nanoseconds. - Weight::from_ref_time(71_401_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 52_539 nanoseconds. + Weight::from_parts(53_490_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_other() -> Weight { - // Minimum execution time: 76_301 nanoseconds. - Weight::from_ref_time(77_302_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 55_013 nanoseconds. + Weight::from_parts(56_275_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_native() -> Weight { - // Minimum execution time: 74_701 nanoseconds. - Weight::from_ref_time(75_601_000) + // Proof Size summary in bytes: + // Measured: `89` + // Estimated: `2603` + // Minimum execution time: 51_466 nanoseconds. + Weight::from_parts(52_439_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:1 w:1) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_other() -> Weight { - // Minimum execution time: 89_502 nanoseconds. - Weight::from_ref_time(90_202_000) + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `7731` + // Minimum execution time: 67_998 nanoseconds. + Weight::from_parts(69_570_000, 7731) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/runtime/altair/src/weights/pallet_scheduler.rs b/runtime/altair/src/weights/pallet_scheduler.rs index a33cb43f75..d23c09c326 100644 --- a/runtime/altair/src/weights/pallet_scheduler.rs +++ b/runtime/altair/src/weights/pallet_scheduler.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_scheduler` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,96 +31,145 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_scheduler`. pub struct WeightInfo(PhantomData); impl pallet_scheduler::WeightInfo for WeightInfo { - // Storage: Scheduler IncompleteSince (r:1 w:1) + /// Storage: Scheduler IncompleteSince (r:1 w:1) + /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { - // Minimum execution time: 7_800 nanoseconds. - Weight::from_ref_time(8_101_000) + // Proof Size summary in bytes: + // Measured: `31` + // Estimated: `499` + // Minimum execution time: 5_740 nanoseconds. + Weight::from_parts(5_961_000, 499) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 50]`. fn service_agenda_base(s: u32, ) -> Weight { - // Minimum execution time: 7_400 nanoseconds. - Weight::from_ref_time(12_679_165) - // Standard Error: 5_246 - .saturating_add(Weight::from_ref_time(987_679).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 5_541 nanoseconds. + Weight::from_parts(7_798_531, 41438) + // Standard Error: 3_448 + .saturating_add(Weight::from_ref_time(1_207_856).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } fn service_task_base() -> Weight { - // Minimum execution time: 17_400 nanoseconds. - Weight::from_ref_time(17_700_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_405 nanoseconds. + Weight::from_ref_time(8_626_000) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - // Minimum execution time: 39_300 nanoseconds. - Weight::from_ref_time(39_701_000) - // Standard Error: 10 - .saturating_add(Weight::from_ref_time(1_771).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `245 + s * (1 ±0)` + // Estimated: `5286 + s * (1 ±0)` + // Minimum execution time: 27_982 nanoseconds. + Weight::from_parts(28_764_000, 5286) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_111).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) } - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn service_task_named() -> Weight { - // Minimum execution time: 26_401 nanoseconds. - Weight::from_ref_time(27_100_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_439 nanoseconds. + Weight::from_ref_time(10_810_000) .saturating_add(T::DbWeight::get().writes(1)) } fn service_task_periodic() -> Weight { - // Minimum execution time: 17_600 nanoseconds. - Weight::from_ref_time(18_000_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_155 nanoseconds. + Weight::from_ref_time(8_466_000) } fn execute_dispatch_signed() -> Weight { - // Minimum execution time: 7_600 nanoseconds. - Weight::from_ref_time(7_801_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_488 nanoseconds. + Weight::from_ref_time(4_629_000) } fn execute_dispatch_unsigned() -> Weight { - // Minimum execution time: 7_500 nanoseconds. - Weight::from_ref_time(7_800_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_359 nanoseconds. + Weight::from_ref_time(4_569_000) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 49]`. fn schedule(s: u32, ) -> Weight { - // Minimum execution time: 30_801 nanoseconds. - Weight::from_ref_time(37_099_890) - // Standard Error: 6_476 - .saturating_add(Weight::from_ref_time(1_071_086).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 19_366 nanoseconds. + Weight::from_parts(22_426_904, 41438) + // Standard Error: 4_263 + .saturating_add(Weight::from_ref_time(1_208_296).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `s` is `[1, 50]`. fn cancel(s: u32, ) -> Weight { - // Minimum execution time: 38_101 nanoseconds. - Weight::from_ref_time(38_844_882) - // Standard Error: 8_832 - .saturating_add(Weight::from_ref_time(1_745_980).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 24_967 nanoseconds. + Weight::from_parts(21_748_563, 41438) + // Standard Error: 5_284 + .saturating_add(Weight::from_ref_time(2_218_951).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 49]`. fn schedule_named(s: u32, ) -> Weight { - // Minimum execution time: 35_901 nanoseconds. - Weight::from_ref_time(43_713_834) - // Standard Error: 9_521 - .saturating_add(Weight::from_ref_time(1_107_084).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `287 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 23_814 nanoseconds. + Weight::from_parts(27_895_396, 43961) + // Standard Error: 4_198 + .saturating_add(Weight::from_ref_time(1_240_886).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { - // Minimum execution time: 40_101 nanoseconds. - Weight::from_ref_time(42_474_738) - // Standard Error: 9_780 - .saturating_add(Weight::from_ref_time(1_753_627).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `313 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 26_830 nanoseconds. + Weight::from_parts(24_874_739, 43961) + // Standard Error: 5_979 + .saturating_add(Weight::from_ref_time(2_232_145).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/altair/src/weights/pallet_session.rs b/runtime/altair/src/weights/pallet_session.rs index be697809a8..3ff13d6a41 100644 --- a/runtime/altair/src/weights/pallet_session.rs +++ b/runtime/altair/src/weights/pallet_session.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,19 +31,29 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:1 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:1 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { - // Minimum execution time: 44_600 nanoseconds. - Weight::from_ref_time(45_600_000) + // Proof Size summary in bytes: + // Measured: `369` + // Estimated: `5688` + // Minimum execution time: 25_598 nanoseconds. + Weight::from_parts(26_740_000, 5688) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:0 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { - // Minimum execution time: 35_901 nanoseconds. - Weight::from_ref_time(36_601_000) + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `3311` + // Minimum execution time: 18_735 nanoseconds. + Weight::from_parts(19_166_000, 3311) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/altair/src/weights/pallet_timestamp.rs b/runtime/altair/src/weights/pallet_timestamp.rs index 5618fe26c0..1bd2920a89 100644 --- a/runtime/altair/src/weights/pallet_timestamp.rs +++ b/runtime/altair/src/weights/pallet_timestamp.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,16 +31,24 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - // Storage: Timestamp Now (r:1 w:1) - // Storage: Aura CurrentSlot (r:1 w:0) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Aura CurrentSlot (r:1 w:0) + /// Proof: Aura CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { - // Minimum execution time: 17_300 nanoseconds. - Weight::from_ref_time(17_800_000) + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `1006` + // Minimum execution time: 14_247 nanoseconds. + Weight::from_parts(15_028_000, 1006) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { - // Minimum execution time: 7_500 nanoseconds. - Weight::from_ref_time(7_701_000) + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `0` + // Minimum execution time: 6_452 nanoseconds. + Weight::from_ref_time(6_753_000) } } diff --git a/runtime/altair/src/weights/pallet_treasury.rs b/runtime/altair/src/weights/pallet_treasury.rs index 982afc6736..ca59c3974d 100644 --- a/runtime/altair/src/weights/pallet_treasury.rs +++ b/runtime/altair/src/weights/pallet_treasury.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_treasury` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -31,56 +32,87 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { fn spend() -> Weight { - // Minimum execution time: 400 nanoseconds. - Weight::from_ref_time(400_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 281 nanoseconds. + Weight::from_ref_time(360_000) } - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { - // Minimum execution time: 48_901 nanoseconds. - Weight::from_ref_time(49_801_000) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `499` + // Minimum execution time: 33_392 nanoseconds. + Weight::from_parts(34_394_000, 499) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Treasury Proposals (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { - // Minimum execution time: 69_701 nanoseconds. - Weight::from_ref_time(70_701_000) + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `7789` + // Minimum execution time: 50_064 nanoseconds. + Weight::from_parts(50_946_000, 7789) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Treasury Proposals (r:1 w:0) - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - // Minimum execution time: 18_300 nanoseconds. - Weight::from_ref_time(25_670_776) - // Standard Error: 3_233 - .saturating_add(Weight::from_ref_time(131_353).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `501 + p * (8 ±0)` + // Estimated: `3480` + // Minimum execution time: 14_517 nanoseconds. + Weight::from_parts(17_952_171, 3480) + // Standard Error: 1_452 + .saturating_add(Weight::from_ref_time(50_722).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { - // Minimum execution time: 15_300 nanoseconds. - Weight::from_ref_time(15_501_000) + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `897` + // Minimum execution time: 11_201 nanoseconds. + Weight::from_parts(11_571_000, 897) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:0) - // Storage: Treasury Deactivated (r:1 w:1) - // Storage: Balances InactiveIssuance (r:1 w:1) - // Storage: Treasury Approvals (r:1 w:1) - // Storage: Treasury Proposals (r:2 w:0) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:100 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - // Minimum execution time: 59_701 nanoseconds. - Weight::from_ref_time(60_487_261) - // Standard Error: 6_116 - .saturating_add(Weight::from_ref_time(3_866_898).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `290 + p * (151 ±0)` + // Estimated: `4522 + p * (2583 ±0)` + // Minimum execution time: 40_906 nanoseconds. + Weight::from_parts(39_006_363, 4522) + // Standard Error: 5_969 + .saturating_add(Weight::from_ref_time(3_723_304).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2583).saturating_mul(p.into())) } } diff --git a/runtime/altair/src/weights/pallet_uniques.rs b/runtime/altair/src/weights/pallet_uniques.rs index 031d2b015d..2b610d680e 100644 --- a/runtime/altair/src/weights/pallet_uniques.rs +++ b/runtime/altair/src/weights/pallet_uniques.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,242 +31,387 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_uniques`. pub struct WeightInfo(PhantomData); impl pallet_uniques::WeightInfo for WeightInfo { - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 53_301 nanoseconds. - Weight::from_ref_time(53_901_000) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2657` + // Minimum execution time: 35_928 nanoseconds. + Weight::from_parts(37_029_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn force_create() -> Weight { - // Minimum execution time: 33_600 nanoseconds. - Weight::from_ref_time(34_300_000) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2657` + // Minimum execution time: 21_150 nanoseconds. + Weight::from_parts(22_072_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:1 w:0) - // Storage: Uniques ClassAccount (r:0 w:1) - // Storage: Uniques Attribute (r:0 w:1000) - // Storage: Uniques ClassMetadataOf (r:0 w:1) - // Storage: Uniques InstanceMetadataOf (r:0 w:1000) - // Storage: Uniques CollectionMaxSupply (r:0 w:1) - // Storage: Uniques Account (r:0 w:20) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1001 w:1000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:0 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:0 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1000) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:0 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 3_525_359 nanoseconds. - Weight::from_ref_time(3_596_960_000) - // Standard Error: 40_336 - .saturating_add(Weight::from_ref_time(14_776_618).saturating_mul(n.into())) - // Standard Error: 40_336 - .saturating_add(Weight::from_ref_time(387_841).saturating_mul(m.into())) - // Standard Error: 40_336 - .saturating_add(Weight::from_ref_time(686_329).saturating_mul(a.into())) + // Proof Size summary in bytes: + // Measured: `543 + n * (121 ±0) + m * (69 ±0) + a * (346 ±0)` + // Estimated: `5270 + n * (2613 ±0)` + // Minimum execution time: 3_029_153 nanoseconds. + Weight::from_parts(3_040_535_000, 5270) + // Standard Error: 30_870 + .saturating_add(Weight::from_ref_time(13_268_500).saturating_mul(n.into())) + // Standard Error: 30_870 + .saturating_add(Weight::from_ref_time(267_061).saturating_mul(m.into())) + // Standard Error: 30_870 + .saturating_add(Weight::from_ref_time(480_057).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(n.into())) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques CollectionMaxSupply (r:1 w:0) - // Storage: Uniques Account (r:0 w:1) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:1 w:0) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn mint() -> Weight { - // Minimum execution time: 66_701 nanoseconds. - Weight::from_ref_time(67_601_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `7773` + // Minimum execution time: 42_850 nanoseconds. + Weight::from_parts(43_992_000, 7773) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:1) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn burn() -> Weight { - // Minimum execution time: 69_802 nanoseconds. - Weight::from_ref_time(70_902_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 44_162 nanoseconds. + Weight::from_parts(45_024_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 54_801 nanoseconds. - Weight::from_ref_time(55_401_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 36_208 nanoseconds. + Weight::from_parts(37_109_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:102 w:102) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:5000 w:5000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 34_400 nanoseconds. - Weight::from_ref_time(34_800_000) - // Standard Error: 19_667 - .saturating_add(Weight::from_ref_time(21_469_706).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `852 + i * (121 ±0)` + // Estimated: `2657 + i * (2613 ±0)` + // Minimum execution time: 19_697 nanoseconds. + Weight::from_parts(20_107_000, 2657) + // Standard Error: 17_498 + .saturating_add(Weight::from_ref_time(20_001_151).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(i.into())) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn freeze() -> Weight { - // Minimum execution time: 40_801 nanoseconds. - Weight::from_ref_time(41_301_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 25_357 nanoseconds. + Weight::from_parts(25_828_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn thaw() -> Weight { - // Minimum execution time: 40_100 nanoseconds. - Weight::from_ref_time(40_700_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 24_896 nanoseconds. + Weight::from_parts(25_838_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn freeze_collection() -> Weight { - // Minimum execution time: 32_700 nanoseconds. - Weight::from_ref_time(33_500_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_775 nanoseconds. + Weight::from_parts(19_337_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn thaw_collection() -> Weight { - // Minimum execution time: 33_100 nanoseconds. - Weight::from_ref_time(33_601_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_475 nanoseconds. + Weight::from_parts(19_196_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:2) + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:2) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // Minimum execution time: 46_100 nanoseconds. - Weight::from_ref_time(46_800_000) + // Proof Size summary in bytes: + // Measured: `463` + // Estimated: `5188` + // Minimum execution time: 28_734 nanoseconds. + Weight::from_parts(29_415_000, 5188) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn set_team() -> Weight { - // Minimum execution time: 33_600 nanoseconds. - Weight::from_ref_time(34_500_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_715 nanoseconds. + Weight::from_parts(19_647_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn force_item_status() -> Weight { - // Minimum execution time: 37_700 nanoseconds. - Weight::from_ref_time(38_300_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 22_502 nanoseconds. + Weight::from_parts(23_334_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // Minimum execution time: 79_601 nanoseconds. - Weight::from_ref_time(80_601_000) + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `8543` + // Minimum execution time: 51_346 nanoseconds. + Weight::from_parts(52_678_000, 8543) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // Minimum execution time: 79_501 nanoseconds. - Weight::from_ref_time(80_301_000) + // Proof Size summary in bytes: + // Measured: `1501` + // Estimated: `8543` + // Minimum execution time: 50_574 nanoseconds. + Weight::from_parts(51_366_000, 8543) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // Minimum execution time: 61_000 nanoseconds. - Weight::from_ref_time(61_701_000) + // Proof Size summary in bytes: + // Measured: `451` + // Estimated: `5463` + // Minimum execution time: 37_811 nanoseconds. + Weight::from_parts(38_743_000, 5463) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // Minimum execution time: 62_201 nanoseconds. - Weight::from_ref_time(63_001_000) + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `5463` + // Minimum execution time: 38_652 nanoseconds. + Weight::from_parts(39_333_000, 5463) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // Minimum execution time: 59_701 nanoseconds. - Weight::from_ref_time(60_601_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5431` + // Minimum execution time: 36_989 nanoseconds. + Weight::from_parts(37_731_000, 5431) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 57_201 nanoseconds. - Weight::from_ref_time(57_901_000) + // Proof Size summary in bytes: + // Measured: `740` + // Estimated: `5431` + // Minimum execution time: 35_246 nanoseconds. + Weight::from_parts(36_217_000, 5431) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // Minimum execution time: 41_801 nanoseconds. - Weight::from_ref_time(43_101_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 26_239 nanoseconds. + Weight::from_parts(26_880_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // Minimum execution time: 41_701 nanoseconds. - Weight::from_ref_time(42_301_000) + // Proof Size summary in bytes: + // Measured: `612` + // Estimated: `5270` + // Minimum execution time: 26_098 nanoseconds. + Weight::from_parts(26_900_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // Minimum execution time: 38_600 nanoseconds. - Weight::from_ref_time(39_201_000) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2531` + // Minimum execution time: 19_968 nanoseconds. + Weight::from_parts(20_679_000, 2531) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques CollectionMaxSupply (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques CollectionMaxSupply (r:1 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 37_100 nanoseconds. - Weight::from_ref_time(37_600_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5160` + // Minimum execution time: 22_643 nanoseconds. + Weight::from_parts(23_504_000, 5160) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:0) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Asset (r:1 w:0) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn set_price() -> Weight { - // Minimum execution time: 37_201 nanoseconds. - Weight::from_ref_time(37_601_000) + // Proof Size summary in bytes: + // Measured: `374` + // Estimated: `2613` + // Minimum execution time: 21_229 nanoseconds. + Weight::from_parts(22_091_000, 2613) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques ItemPriceOf (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Account (r:0 w:2) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:1 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn buy_item() -> Weight { - // Minimum execution time: 71_101 nanoseconds. - Weight::from_ref_time(71_901_000) + // Proof Size summary in bytes: + // Measured: `739` + // Estimated: `7850` + // Minimum execution time: 50_534 nanoseconds. + Weight::from_parts(51_256_000, 7850) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/runtime/altair/src/weights/pallet_utility.rs b/runtime/altair/src/weights/pallet_utility.rs index 5bba94cc2f..a172184de2 100644 --- a/runtime/altair/src/weights/pallet_utility.rs +++ b/runtime/altair/src/weights/pallet_utility.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -32,31 +33,46 @@ pub struct WeightInfo(PhantomData); impl pallet_utility::WeightInfo for WeightInfo { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - // Minimum execution time: 27_801 nanoseconds. - Weight::from_ref_time(31_985_893) - // Standard Error: 2_970 - .saturating_add(Weight::from_ref_time(7_709_673).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_570 nanoseconds. + Weight::from_ref_time(11_897_050) + // Standard Error: 4_245 + .saturating_add(Weight::from_ref_time(8_352_707).saturating_mul(c.into())) } fn as_derivative() -> Weight { - // Minimum execution time: 17_701 nanoseconds. - Weight::from_ref_time(18_100_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_085 nanoseconds. + Weight::from_ref_time(8_316_000) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - // Minimum execution time: 32_600 nanoseconds. - Weight::from_ref_time(242_038_038) - // Standard Error: 34_774 - .saturating_add(Weight::from_ref_time(7_800_363).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_630 nanoseconds. + Weight::from_ref_time(9_851_717) + // Standard Error: 2_987 + .saturating_add(Weight::from_ref_time(8_764_338).saturating_mul(c.into())) } fn dispatch_as() -> Weight { - // Minimum execution time: 25_000 nanoseconds. - Weight::from_ref_time(25_601_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_886 nanoseconds. + Weight::from_ref_time(14_317_000) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - // Minimum execution time: 21_300 nanoseconds. - Weight::from_ref_time(32_068_401) - // Standard Error: 2_397 - .saturating_add(Weight::from_ref_time(7_698_561).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_760 nanoseconds. + Weight::from_ref_time(10_725_392) + // Standard Error: 2_682 + .saturating_add(Weight::from_ref_time(8_346_859).saturating_mul(c.into())) } } diff --git a/runtime/altair/src/weights/pallet_vesting.rs b/runtime/altair/src/weights/pallet_vesting.rs index cfdd0bf390..788ef94a4b 100644 --- a/runtime/altair/src/weights/pallet_vesting.rs +++ b/runtime/altair/src/weights/pallet_vesting.rs @@ -2,8 +2,9 @@ //! Autogenerated weights for `pallet_vesting` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 // Executed Command: @@ -30,119 +31,167 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_vesting`. pub struct WeightInfo(PhantomData); impl pallet_vesting::WeightInfo for WeightInfo { - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. - fn vest_locked(_l: u32, s: u32, ) -> Weight { - // Minimum execution time: 70_701 nanoseconds. - Weight::from_ref_time(78_218_829) - // Standard Error: 29_665 - .saturating_add(Weight::from_ref_time(105_024).saturating_mul(s.into())) + fn vest_locked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `334 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 37_199 nanoseconds. + Weight::from_parts(37_164_502, 7306) + // Standard Error: 1_575 + .saturating_add(Weight::from_ref_time(31_267).saturating_mul(l.into())) + // Standard Error: 2_803 + .saturating_add(Weight::from_ref_time(78_671).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 69_702 nanoseconds. - Weight::from_ref_time(69_877_977) - // Standard Error: 3_045 - .saturating_add(Weight::from_ref_time(61_261).saturating_mul(l.into())) - // Standard Error: 5_418 - .saturating_add(Weight::from_ref_time(103_798).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `334 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 37_029 nanoseconds. + Weight::from_parts(36_905_678, 7306) + // Standard Error: 1_227 + .saturating_add(Weight::from_ref_time(24_900).saturating_mul(l.into())) + // Standard Error: 2_183 + .saturating_add(Weight::from_ref_time(70_717).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 70_901 nanoseconds. - Weight::from_ref_time(71_204_021) - // Standard Error: 4_252 - .saturating_add(Weight::from_ref_time(67_255).saturating_mul(l.into())) - // Standard Error: 7_566 - .saturating_add(Weight::from_ref_time(127_963).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `469 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 40_646 nanoseconds. + Weight::from_parts(40_147_372, 9909) + // Standard Error: 1_320 + .saturating_add(Weight::from_ref_time(33_153).saturating_mul(l.into())) + // Standard Error: 2_349 + .saturating_add(Weight::from_ref_time(87_082).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 70_101 nanoseconds. - Weight::from_ref_time(70_715_097) - // Standard Error: 3_579 - .saturating_add(Weight::from_ref_time(55_730).saturating_mul(l.into())) - // Standard Error: 6_368 - .saturating_add(Weight::from_ref_time(88_332).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `469 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 40_676 nanoseconds. + Weight::from_parts(40_308_306, 9909) + // Standard Error: 1_330 + .saturating_add(Weight::from_ref_time(29_765).saturating_mul(l.into())) + // Standard Error: 2_367 + .saturating_add(Weight::from_ref_time(73_503).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 101_602 nanoseconds. - Weight::from_ref_time(102_939_896) - // Standard Error: 4_934 - .saturating_add(Weight::from_ref_time(67_912).saturating_mul(l.into())) - // Standard Error: 8_779 - .saturating_add(Weight::from_ref_time(81_860).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `540 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 60_854 nanoseconds. + Weight::from_parts(62_016_980, 9909) + // Standard Error: 4_300 + .saturating_add(Weight::from_ref_time(35_984).saturating_mul(l.into())) + // Standard Error: 7_650 + .saturating_add(Weight::from_ref_time(45_184).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 101_501 nanoseconds. - Weight::from_ref_time(103_521_103) - // Standard Error: 5_674 - .saturating_add(Weight::from_ref_time(61_845).saturating_mul(l.into())) - // Standard Error: 10_096 - .saturating_add(Weight::from_ref_time(56_307).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `712 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12512` + // Minimum execution time: 64_861 nanoseconds. + Weight::from_parts(66_489_132, 12512) + // Standard Error: 3_639 + .saturating_add(Weight::from_ref_time(22_379).saturating_mul(l.into())) + // Standard Error: 6_474 + .saturating_add(Weight::from_ref_time(28_188).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 72_901 nanoseconds. - Weight::from_ref_time(72_516_407) - // Standard Error: 3_169 - .saturating_add(Weight::from_ref_time(75_514).saturating_mul(l.into())) - // Standard Error: 5_853 - .saturating_add(Weight::from_ref_time(144_819).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 42_189 nanoseconds. + Weight::from_parts(41_721_083, 9909) + // Standard Error: 1_263 + .saturating_add(Weight::from_ref_time(35_062).saturating_mul(l.into())) + // Standard Error: 2_332 + .saturating_add(Weight::from_ref_time(87_442).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 72_902 nanoseconds. - Weight::from_ref_time(71_703_899) - // Standard Error: 3_509 - .saturating_add(Weight::from_ref_time(84_180).saturating_mul(l.into())) - // Standard Error: 6_481 - .saturating_add(Weight::from_ref_time(157_975).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 42_288 nanoseconds. + Weight::from_parts(41_956_062, 9909) + // Standard Error: 1_286 + .saturating_add(Weight::from_ref_time(34_042).saturating_mul(l.into())) + // Standard Error: 2_376 + .saturating_add(Weight::from_ref_time(80_324).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/runtime/altair/src/xcm.rs b/runtime/altair/src/xcm.rs index e8838798f4..d285fa7af7 100644 --- a/runtime/altair/src/xcm.rs +++ b/runtime/altair/src/xcm.rs @@ -11,7 +11,6 @@ // GNU General Public License for more details. use cfg_primitives::{ - constants::currency_decimals, parachains, types::{EnsureRootOr, HalfOfCouncil}, }; @@ -22,18 +21,22 @@ pub use frame_support::{ traits::{Contains, Everything, Get, Nothing}, weights::Weight, }; -use frame_support::{sp_std::marker::PhantomData, traits::fungibles}; +use frame_support::{ + sp_std::marker::PhantomData, + traits::{fungibles, fungibles::Mutate}, +}; use orml_asset_registry::{AssetRegistryTrader, FixedRateAssetRegistryTrader}; -use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; use orml_xcm_support::MultiNativeAsset; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use runtime_common::{ xcm::{general_key, AccountIdToMultiLocation, FixedConversionRateProvider}, - xcm_fees::{default_per_second, ksm_per_second, native_per_second}, + xcm_fees::native_per_second, }; use sp_core::ConstU32; use sp_runtime::traits::{Convert, Zero}; +pub use xcm::v3::{MultiAsset, MultiLocation}; use xcm::{prelude::*, v3::Weight as XcmWeight}; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, @@ -45,10 +48,41 @@ use xcm_builder::{ use xcm_executor::{traits::JustTry, XcmExecutor}; use super::{ - AccountId, Balance, OrmlAssetRegistry, OrmlTokens, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, + AccountId, Balance, OrmlAssetRegistry, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, }; +/// A call filter for the XCM Transact instruction. This is a temporary +/// measure until we properly account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call +/// parameters. +/// +/// NOTE: Defensive configuration for now, inspired by filter of +/// SystemParachains and Polkadot, can be extended if desired. +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::Timestamp(..) + | RuntimeCall::Balances(..) + | RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) + | RuntimeCall::PolkadotXcm( + pallet_xcm::Call::limited_reserve_transfer_assets { .. } + ) | RuntimeCall::XcmpQueue(..) + | RuntimeCall::DmpQueue(..) + | RuntimeCall::Proxy(..) + | RuntimeCall::LiquidityPoolsGateway( + pallet_liquidity_pools_gateway::Call::process_msg { .. } + ) // TODO: Enable later: | RuntimeCall::OrderBook(..) + ) + } +} + /// The main XCM config /// This is where we configure the core of our XCM integrations: how tokens are /// transferred, how fees are calculated, what barriers we impose on incoming @@ -72,7 +106,7 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = crate::AllPalletsWithSystem; type ResponseHandler = PolkadotXcm; type RuntimeCall = RuntimeCall; - type SafeCallFilter = Everything; + type SafeCallFilter = SafeCallFilter; type SubscriptionService = PolkadotXcm; type Trader = Trader; type UniversalAliases = Nothing; @@ -103,28 +137,6 @@ parameter_types! { native_per_second(), 0, ); - - pub AirPerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2(Parachain(ParachainInfo::parachain_id().into()), general_key(parachains::kusama::altair::AIR_KEY)), - ).into(), - native_per_second(), - ); - - pub KsmPerSecond: (AssetId, u128) = (MultiLocation::parent().into(), ksm_per_second()); - - pub AUSDPerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key(parachains::kusama::karura::AUSD_KEY) - ) - ).into(), - default_per_second(currency_decimals::AUSD) - ); - } pub struct ToTreasury; @@ -140,7 +152,7 @@ impl TakeRevenue for ToTreasury { if let Ok(currency_id) = >::convert(location) { - let _ = OrmlTokens::deposit(currency_id, &TreasuryAccount::get(), amount); + let _ = Tokens::mint_into(currency_id, &TreasuryAccount::get(), amount); } } } @@ -220,10 +232,12 @@ impl xcm_executor::traits::Convert for CurrencyIdConv let unanchored_location = match location { MultiLocation { parents: 0, - interior: X1(x), + interior, } => MultiLocation { parents: 1, - interior: X2(Parachain(u32::from(ParachainInfo::get())), x), + interior: interior + .pushed_front_with(Parachain(u32::from(ParachainInfo::get()))) + .map_err(|_| location)?, }, x => x, }; @@ -265,7 +279,7 @@ impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type SendXcmOrigin = EnsureXcmOrigin; - type SovereignAccountOf = (); + type SovereignAccountOf = LocationToAccountId; type TrustedLockers = (); type UniversalLocation = UniversalLocation; type Weigher = FixedWeightBounds; @@ -280,7 +294,6 @@ impl pallet_xcm::Config for Runtime { } parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); @@ -298,6 +311,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Generate remote accounts according to polkadot standards + cfg_primitives::xcm::HashedDescriptionDescribeFamilyAllTerminal, ); /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -313,9 +328,9 @@ pub type XcmRouter = ( ); /// This is the type we use to convert an (incoming) XCM origin into a local -/// `Origin` instance, ready for dispatching a transaction with Xcm's +/// `RuntimeOrigin` instance, ready for dispatching a transaction with Xcm's /// `Transact`. There is an `OriginKind` which can biases the kind of local -/// `Origin` it will become. +/// `RuntimeOrigin` it will become. pub type XcmOriginToTransactDispatchOrigin = ( // Sovereign account converter; this attempts to derive an `AccountId` from the origin location // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for diff --git a/runtime/centrifuge/Cargo.toml b/runtime/centrifuge/Cargo.toml index 28745858bd..cb6a21f766 100644 --- a/runtime/centrifuge/Cargo.toml +++ b/runtime/centrifuge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "centrifuge-runtime" -version = "0.10.19" +version = "0.10.20" authors = ["Centrifuge "] edition = "2021" build = "build.rs" @@ -11,7 +11,7 @@ repository = "https://github.com/centrifuge/centrifuge-chain" [dependencies] # third-party dependencies codec = { package = "parity-scale-codec", version = "3.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.3.4", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } serde = { version = "1.0.119", optional = true } @@ -55,7 +55,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features # frame dependencies frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, features = ["tuples-96"], branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -101,9 +101,11 @@ pallet-evm-chain-id = { git = "https://github.com/PureStake/frontier", default-f pallet-evm-precompile-dispatch = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } # Our pallets and modules +axelar-gateway-precompile = { path = "../../pallets/liquidity-pools-gateway/axelar-gateway-precompile", default-features = false } cfg-primitives = { path = "../../libs/primitives", default-features = false } cfg-traits = { path = "../../libs/traits", default-features = false } cfg-types = { path = "../../libs/types", default-features = false } +liquidity-pools-gateway-routers = { path = "../../pallets/liquidity-pools-gateway/routers", default-features = false } pallet-anchors = { path = "../../pallets/anchors", default-features = false } pallet-block-rewards = { path = "../../pallets/block-rewards", default-features = false } pallet-bridge = { path = "../../pallets/bridge", default-features = false } @@ -112,11 +114,15 @@ pallet-collator-allowlist = { path = "../../pallets/collator-allowlist", default pallet-crowdloan-claim = { path = "../../pallets/crowdloan-claim", default-features = false } pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-features = false } pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } +pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } # pallet-foreign-investments = { path = "../../pallets/foreign-investments", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-keystore = { path = "../../pallets/keystore", default-features = false } +pallet-liquidity-pools = { path = "../../pallets/liquidity-pools", default-features = false } +pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway", default-features = false } +pallet-liquidity-rewards = { path = "../../pallets/liquidity-rewards", default-features = false } pallet-loans = { path = "../../pallets/loans", default-features = false } pallet-migration-manager = { path = "../../pallets/migration", default-features = false } pallet-nft = { path = "../../pallets/nft", default-features = false } @@ -127,6 +133,11 @@ pallet-restricted-tokens = { path = "../../pallets/restricted-tokens", default-f pallet-rewards = { path = "../../pallets/rewards", default-features = false } runtime-common = { path = "../common", default-features = false } +# LiquidityPools 3rd-party dependencies +moonbeam-relay-encoder = { git = "https://github.com/PureStake/moonbeam", default-features = false, rev = "00b3e3d97806e889b02e1bcb4b69e65433dd805d" } +pallet-xcm-transactor = { git = "https://github.com/PureStake/moonbeam", default-features = false, rev = "00b3e3d97806e889b02e1bcb4b69e65433dd805d" } +xcm-primitives = { git = "https://github.com/PureStake/moonbeam", default-features = false, rev = "00b3e3d97806e889b02e1bcb4b69e65433dd805d" } + # bridge pallets chainbridge = { git = "https://github.com/centrifuge/chainbridge-substrate.git", default-features = false, branch = "polkadot-v0.9.38" } @@ -160,6 +171,8 @@ std = [ "frame-system-rpc-runtime-api/std", "frame-system/std", "frame-try-runtime/std", + "liquidity-pools-gateway-routers/std", + "moonbeam-relay-encoder/std", "orml-asset-registry/std", "orml-tokens/std", "orml-traits/std", @@ -184,6 +197,7 @@ std = [ "pallet-democracy/std", "pallet-elections-phragmen/std", "pallet-ethereum/std", + "pallet-ethereum-transaction/std", "pallet-evm/std", "pallet-evm-precompile-dispatch/std", "pallet-evm-chain-id/std", @@ -192,6 +206,9 @@ std = [ "pallet-identity/std", "pallet-interest-accrual/std", "pallet-investments/std", + "pallet-liquidity-pools/std", + "pallet-liquidity-pools-gateway/std", + "pallet-liquidity-rewards/std", "pallet-loans/std", "pallet-keystore/std", "pallet-migration-manager/std", @@ -216,6 +233,7 @@ std = [ "pallet-utility/std", "pallet-vesting/std", "pallet-xcm/std", + "pallet-xcm-transactor/std", "parachain-info/std", "polkadot-parachain/std", "polkadot-runtime-common/std", @@ -236,7 +254,9 @@ std = [ "sp-version/std", "xcm-builder/std", "xcm-executor/std", + "xcm-primitives/std", "xcm/std", + "axelar-gateway-precompile/std", ] runtime-benchmarks = [ @@ -251,7 +271,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "hex-literal", + "liquidity-pools-gateway-routers/runtime-benchmarks", "orml-asset-registry/runtime-benchmarks", "orml-tokens/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", @@ -268,12 +288,16 @@ runtime-benchmarks = [ "pallet-democracy/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-ethereum/runtime-benchmarks", + "pallet-ethereum-transaction/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", # "pallet-foreign-investments/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", + "pallet-liquidity-pools/runtime-benchmarks", + "pallet-liquidity-pools-gateway/runtime-benchmarks", + "pallet-liquidity-rewards/runtime-benchmarks", "pallet-loans/runtime-benchmarks", "pallet-keystore/runtime-benchmarks", "pallet-migration-manager/runtime-benchmarks", @@ -293,14 +317,17 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", "polkadot-parachain/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-primitives/runtime-benchmarks", "pallet-claims/runtime-benchmarks", "pallet-rewards/runtime-benchmarks", + "axelar-gateway-precompile/runtime-benchmarks", ] try-runtime = [ @@ -318,6 +345,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime", + "liquidity-pools-gateway-routers/try-runtime", "orml-asset-registry/try-runtime", "orml-tokens/try-runtime", "orml-xcm/try-runtime", @@ -340,6 +368,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-ethereum/try-runtime", + "pallet-ethereum-transaction/try-runtime", "pallet-evm/try-runtime", "pallet-evm-chain-id/try-runtime", "pallet-fees/try-runtime", @@ -347,6 +376,9 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-interest-accrual/try-runtime", "pallet-investments/try-runtime", + "pallet-liquidity-pools/try-runtime", + "pallet-liquidity-pools-gateway/try-runtime", + "pallet-liquidity-rewards/try-runtime", "pallet-loans/try-runtime", "pallet-keystore/try-runtime", "pallet-migration-manager/try-runtime", @@ -370,10 +402,12 @@ try-runtime = [ "pallet-utility/try-runtime", "pallet-vesting/try-runtime", "pallet-xcm/try-runtime", + "pallet-xcm-transactor/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", "runtime-common/try-runtime", "sp-runtime/try-runtime", + "axelar-gateway-precompile/try-runtime", ] # A feature that should be enabled when the runtime should be build for on-chain diff --git a/runtime/centrifuge/src/evm.rs b/runtime/centrifuge/src/evm.rs index b7e0ae2f78..dd772d265a 100644 --- a/runtime/centrifuge/src/evm.rs +++ b/runtime/centrifuge/src/evm.rs @@ -10,18 +10,19 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::{MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; +use cfg_primitives::{TwoThirdOfCouncil, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; use frame_support::{parameter_types, traits::FindAuthor, weights::Weight, ConsensusEngineId}; use pallet_evm::{EnsureAddressRoot, EnsureAddressTruncated}; use runtime_common::{ account_conversion::AccountConverter, evm::{precompile::CentrifugePrecompiles, BaseFeeThreshold, WEIGHT_PER_GAS}, + origin::EnsureAccountOrRootOr, }; use sp_core::{crypto::ByteArray, H160, U256}; use sp_runtime::Permill; use sp_std::marker::PhantomData; -use crate::Aura; +use crate::{Aura, LocationToAccountId}; // To create valid Ethereum-compatible blocks, we need a 20-byte // "author" for the block. Since that author is purely informational, @@ -47,7 +48,7 @@ parameter_types! { } impl pallet_evm::Config for crate::Runtime { - type AddressMapping = AccountConverter; + type AddressMapping = AccountConverter; type BlockGasLimit = BlockGasLimit; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressRoot; @@ -84,3 +85,11 @@ impl pallet_ethereum::Config for crate::Runtime { type RuntimeEvent = crate::RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; } + +impl pallet_ethereum_transaction::Config for crate::Runtime {} + +impl axelar_gateway_precompile::Config for crate::Runtime { + type AdminOrigin = EnsureAccountOrRootOr; + type RuntimeEvent = crate::RuntimeEvent; + type WeightInfo = (); +} diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 8c765c19c9..a6a95dd28d 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -22,10 +22,13 @@ pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as _}, + liquidity_pools::{InboundQueue, OutboundQueue}, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, StatusNotificationHook, + TryConvert, }; use cfg_types::{ consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes}, + domain_address::{Domain, DomainAddress}, fee_keys::FeeKey, fixed_point::{Quantity, Rate}, ids::PRICE_ORACLE_PALLET_ID, @@ -62,7 +65,7 @@ use orml_traits::{currency::MutationHooks, parameter_type_with_key}; use pallet_anchors::AnchorData; pub use pallet_balances::Call as BalancesCall; use pallet_collective::{EnsureMember, EnsureProportionAtLeast, EnsureProportionMoreThan}; -use pallet_ethereum::Transaction as EthereumTransaction; +use pallet_ethereum::Transaction as EthTransaction; use pallet_evm::{Account as EVMAccount, FeeCalculator, Runner}; use pallet_investments::OrderType; use pallet_pool_system::{ @@ -77,6 +80,7 @@ pub use pallet_timestamp::Call as TimestampCall; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, RuntimeDispatchInfo}; use polkadot_runtime_common::{prod_or_fast, BlockHashCount, SlowAdjustingFeeUpdate}; +use runtime_common::{account_conversion::AccountConverter, xcm::AccountIdToMultiLocation}; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; use sp_core::{OpaqueMetadata, H160, H256, U256}; @@ -99,7 +103,7 @@ use sp_version::RuntimeVersion; use static_assertions::const_assert; use xcm_executor::XcmExecutor; -use crate::xcm::{XcmConfig, XcmOriginToTransactDispatchOrigin}; +use crate::xcm::{MultiAsset, MultiLocation, XcmConfig, XcmOriginToTransactDispatchOrigin}; pub mod evm; mod migrations; @@ -129,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge"), impl_name: create_runtime_str!("centrifuge"), authoring_version: 1, - spec_version: 1019, + spec_version: 1020, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -258,7 +262,14 @@ impl Contains for BaseCallFilter { | pallet_xcm::Call::force_subscribe_version_notify { .. } | pallet_xcm::Call::force_unsubscribe_version_notify { .. } => true, }, - RuntimeCall::EVM(_) => false, // Disable allnon-root EVM access + // Disable all non-root EVM access + RuntimeCall::EVM(_) => false, + // We block this call since it includes Moonbeam trait implementations such + // as UtilityEncodeCall and XcmTransact that we don't implement and don't want + // arbitrary users calling it. + RuntimeCall::XcmTransactor( + pallet_xcm_transactor::Call::transact_through_derivative { .. }, + ) => false, _ => true, } } @@ -418,6 +429,113 @@ impl orml_asset_registry::Config for Runtime { type WeightInfo = (); } +parameter_types! { + // To be used if we want to register a particular asset in the chain spec, when running the chain locally. + pub LiquidityPoolsPalletIndex: PalletIndex = ::index() as u8; +} + +impl pallet_liquidity_pools::Config for Runtime { + type AdminOrigin = EnsureRootOr; + type AssetRegistry = OrmlAssetRegistry; + type Balance = Balance; + type BalanceRatio = Quantity; + type CurrencyId = CurrencyId; + type DomainAccountToAccountId = AccountConverter; + type DomainAddressToAccountId = AccountConverter; + type ForeignInvestment = Investments; + type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; + type OutboundQueue = FilteredOutboundQueue; + type Permission = Permissions; + type PoolId = PoolId; + type PoolInspect = PoolSystem; + type RuntimeEvent = RuntimeEvent; + type Time = Timestamp; + type Tokens = Tokens; + type TrancheCurrency = TrancheCurrency; + type TrancheId = TrancheId; + type TrancheTokenPrice = PoolSystem; + type TreasuryAccount = TreasuryAccount; + type WeightInfo = (); +} + +type LiquidityPoolsMessage = + pallet_liquidity_pools::Message; + +/// The FilteredOutboundQueue serves as a filter for outbound LP messages that +/// we want to allow initially. +pub struct FilteredOutboundQueue; + +impl OutboundQueue for FilteredOutboundQueue { + type Destination = Domain; + type Message = LiquidityPoolsMessage; + type Sender = AccountId; + + fn submit( + sender: Self::Sender, + destination: Self::Destination, + msg: Self::Message, + ) -> DispatchResult { + match msg { + LiquidityPoolsMessage::AddCurrency { .. } + | LiquidityPoolsMessage::UpdateMember { .. } + | LiquidityPoolsMessage::AddPool { .. } + | LiquidityPoolsMessage::AddTranche { .. } + | LiquidityPoolsMessage::UpdateTrancheTokenPrice { .. } => { + ::submit(sender, destination, msg) + } + _ => Err(DispatchError::Other("unsupported outbound message")), + } + } +} + +parameter_types! { + pub const MaxIncomingMessageSize: u32 = 1024; + pub Sender: AccountId = GatewayAccountProvider::::get_gateway_account(); +} + +parameter_types! { + // A temporary admin account for the LP logic + // This is a multi-sig controlled pure proxy on mainnet + // - address: "4eEqmbQMbFfNUg6bQnqi9zgUvQvSpNbUgstEM64Xq9FW58Xv" (on Centrifuge) + // (pub key 0x80339e91a87b9c082705fd1a6d39b3e00b46e445ad8c80c127f6a56941c6aa57) + // + // This account is besides Root and 2/3-council able to + // - add valid relayer contracts + // - rm valid relayer contracts + // - add valid LP instance contracts + // - rm valid LP instance contracts + // - add conversions from Axelar `sourceChain` strings to `DomainAddress` + // - set the Axelar gateway contract in the Axelar gateway precompile + pub LpAdminAccount: AccountId = AccountId::new(hex_literal::hex!("80339e91a87b9c082705fd1a6d39b3e00b46e445ad8c80c127f6a56941c6aa57")); +} + +impl pallet_liquidity_pools_gateway::Config for Runtime { + type AdminOrigin = EnsureAccountOrRootOr; + type InboundQueue = DummyInboundQueue; + type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; + type MaxIncomingMessageSize = MaxIncomingMessageSize; + type Message = LiquidityPoolsMessage; + type OriginRecovery = crate::LiquidityPoolsAxelarGateway; + type Router = liquidity_pools_gateway_routers::DomainRouter; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type Sender = Sender; + type WeightInfo = (); +} + +/// DummyInboundQueue will be used in the first phase of testing in order to +/// ensure that no incoming messages will be processed. +pub struct DummyInboundQueue; + +impl InboundQueue for DummyInboundQueue { + type Message = LiquidityPoolsMessage; + type Sender = DomainAddress; + + fn submit(_: Self::Sender, _: Self::Message) -> DispatchResult { + Err(DispatchError::Other("InboundQueue not supported yet")) + } +} + impl pallet_randomness_collective_flip::Config for Runtime {} impl parachain_info::Config for Runtime {} @@ -1180,15 +1298,45 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = weights::pallet_collator_selection::WeightInfo; } +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = xcm_builder::FixedWeightBounds; + +parameter_types! { + // 1 DOT, which has 10 decimals, should be enough to cover for fees opening/accepting hrmp channels. + pub MaxHrmpRelayFee: MultiAsset = (MultiLocation::parent(), 10_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type AccountIdToMultiLocation = AccountIdToMultiLocation; + type AssetTransactor = FungiblesTransactor; + type Balance = Balance; + type BaseXcmWeight = BaseXcmWeight; + type CurrencyId = CurrencyId; + type CurrencyIdToMultiLocation = xcm::CurrencyIdConvert; + type DerivativeAddressRegistrationOrigin = EnsureRootOr; + type HrmpEncoder = moonbeam_relay_encoder::polkadot::PolkadotEncoder; + type HrmpManipulatorOrigin = EnsureRootOr; + type MaxHrmpFee = xcm_builder::Case; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RuntimeEvent = RuntimeEvent; + type SelfLocation = SelfLocation; + type SovereignAccountDispatcherOrigin = EnsureRootOr; + type Transactor = xcm_transactor::NullTransactor; + type UniversalLocation = UniversalLocation; + type Weigher = XcmWeigher; + type WeightInfo = (); + type XcmSender = XcmRouter; +} + // Block Rewards -frame_support::parameter_types! { +parameter_types! { // BlockRewards have exactly one group and currency #[derive(scale_info::TypeInfo)] pub const SingleCurrencyMovement: u32 = 1; #[derive(scale_info::TypeInfo, Debug, PartialEq, Eq, Clone)] pub const MaxChangesPerEpoch: u32 = 50; - pub const RewardsPalletId: PalletId = cfg_types::ids::BLOCK_REWARDS_PALLET_ID; + pub const BlockRewardsPalletId: PalletId = cfg_types::ids::BLOCK_REWARDS_PALLET_ID; pub const RewardCurrency: CurrencyId = CurrencyId::Native; } @@ -1196,7 +1344,7 @@ impl pallet_rewards::Config for Runtime { type Currency = Tokens; type CurrencyId = CurrencyId; type GroupId = u32; - type PalletId = RewardsPalletId; + type PalletId = BlockRewardsPalletId; type RewardCurrency = RewardCurrency; // Must not change this to ensure block rewards are minted type RewardIssuance = @@ -1210,7 +1358,7 @@ impl pallet_rewards::Config for Runtime { type RuntimeEvent = RuntimeEvent; } -frame_support::parameter_types! { +parameter_types! { pub const BlockRewardCurrency: CurrencyId = CurrencyId::Staking(StakingCurrency::BlockRewards); pub const StakeAmount: Balance = cfg_types::consts::rewards::DEFAULT_COLLATOR_STAKE; pub const CollatorGroupId: u32 = cfg_types::ids::COLLATOR_GROUP_ID; @@ -1235,6 +1383,52 @@ impl pallet_block_rewards::Config for Runtime { type WeightInfo = weights::pallet_block_rewards::WeightInfo; } +// Liquidity rewards + +parameter_types! { + #[derive(scale_info::TypeInfo)] + pub const MaxCurrencyMovements: u32 = 50; + #[derive(scale_info::TypeInfo)] + pub const MaxGroups: u32 = 20; + pub const LiquidityRewardsPalletId: PalletId = cfg_types::ids::LIQUIDITY_REWARDS_PALLET_ID; + pub const InitialEpochDuration: Moment = SECONDS_PER_MINUTE * 1000; // 1 min in milliseconds +} + +impl pallet_rewards::mechanism::gap::Config for Runtime { + type Balance = Balance; + type DistributionId = u32; + type IBalance = IBalance; + type MaxCurrencyMovements = MaxCurrencyMovements; + type Rate = FixedI128; +} + +impl pallet_liquidity_rewards::Config for Runtime { + type AdminOrigin = EnsureRootOr; + type Balance = Balance; + type CurrencyId = CurrencyId; + type GroupId = u32; + type InitialEpochDuration = InitialEpochDuration; + type MaxChangesPerEpoch = MaxChangesPerEpoch; + type MaxGroups = MaxGroups; + type Rewards = LiquidityRewardsBase; + type RuntimeEvent = RuntimeEvent; + type Timer = Timestamp; + type Weight = u64; + type WeightInfo = weights::pallet_liquidity_rewards::WeightInfo; +} + +impl pallet_rewards::Config for Runtime { + type Currency = Tokens; + type CurrencyId = CurrencyId; + type GroupId = u32; + type PalletId = LiquidityRewardsPalletId; + type RewardCurrency = RewardCurrency; + type RewardIssuance = + pallet_rewards::issuance::MintReward; + type RewardMechanism = GapRewardMechanism; + type RuntimeEvent = RuntimeEvent; +} + // Pool config parameters parameter_types! { pub const PoolPalletId: frame_support::PalletId = cfg_types::ids::POOLS_PALLET_ID; @@ -1381,7 +1575,6 @@ impl pallet_pool_registry::Config for Runtime { type Permission = Permissions; type PoolCreateOrigin = EnsureRoot; type PoolId = PoolId; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; @@ -1391,6 +1584,7 @@ impl pallet_pool_registry::Config for Runtime { impl pallet_pool_system::Config for Runtime { type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; + type BalanceRatio = Quantity; type ChallengeTime = ChallengeTime; type Currency = Balances; type CurrencyId = CurrencyId; @@ -1563,10 +1757,9 @@ impl StatusNotificationHook for NoopCollectHook { impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = NoopCollectHook; type CollectedRedemptionHook = NoopCollectHook; - type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = IsTrancheInvestor; type RuntimeEvent = RuntimeEvent; @@ -1638,12 +1831,6 @@ impl pallet_data_collector::Config for Runtime { type Moment = Moment; } -parameter_types! { - // todo(nuno): make it `pub LiquidityPoolsPalletIndex: PalletIndex = ::index() as u8;` - // once we have LiquidityPools - pub const LiquidityPoolsPalletIndex: PalletIndex = 103; -} - impl pallet_interest_accrual::Config for Runtime { type Balance = Balance; // TODO: This is a stopgap value until we can calculate it correctly with @@ -1787,15 +1974,19 @@ construct_runtime!( BlockRewardsBase: pallet_rewards::::{Pallet, Storage, Event, Config} = 100, BlockRewards: pallet_block_rewards::{Pallet, Call, Storage, Event, Config} = 101, PriceCollector: pallet_data_collector::{Pallet, Storage} = 102, - // RESERVED 103 index for LiquidityPools - // LiquidityPools: pallet_liquidity_pools::{Pallet, Call, Storage, Event} = 103, + LiquidityPools: pallet_liquidity_pools::{Pallet, Call, Storage, Event} = 103, + LiquidityRewardsBase: pallet_rewards::::{Pallet, Storage, Event, Config} = 104, + LiquidityRewards: pallet_liquidity_rewards::{Pallet, Call, Storage, Event} = 105, + GapRewardMechanism: pallet_rewards::mechanism::gap = 106, + LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 107, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 121, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Config, Event, Origin} = 121, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 122, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 123, XTokens: orml_xtokens::{Pallet, Storage, Call, Event} = 124, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Storage, Event} = 125, // 3rd party pallets ChainBridge: chainbridge::{Pallet, Call, Storage, Event} = 150, @@ -1810,6 +2001,8 @@ construct_runtime!( EVMChainId: pallet_evm_chain_id::{Pallet, Config, Storage} = 161, BaseFee: pallet_base_fee::{Pallet, Call, Config, Storage, Event} = 162, Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 163, + EthereumTransaction: pallet_ethereum_transaction::{Pallet, Storage} = 164, + LiquidityPoolsAxelarGateway: axelar_gateway_precompile::{Pallet, Call, Storage, Event} = 165, // Synced pallets across all runtimes - Range: 180-240 // WHY: * integrations like fireblocks will need to know the index in the enum @@ -1857,7 +2050,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - migrations::UpgradeCentrifuge1020, + migrations::UpgradeCentrifuge1021, >; pub struct TransactionConverter; @@ -1887,10 +2080,12 @@ impl fp_rpc::ConvertTransaction for TransactionConv #[cfg(not(feature = "disable-runtime-api"))] mod __runtime_api_use { pub use pallet_loans::entities::loans::ActiveLoanInfo; + pub use runtime_common::account_conversion::AccountConverter; } #[cfg(not(feature = "disable-runtime-api"))] use __runtime_api_use::*; +use runtime_common::{gateway::GatewayAccountProvider, origin::EnsureAccountOrRootOr}; #[cfg(not(feature = "disable-runtime-api"))] impl_runtime_apis! { @@ -2030,7 +2225,7 @@ impl_runtime_apis! { let index: usize = pool.tranches.tranche_index(&tranche)?.try_into().ok()?; let prices = pool .tranches - .calculate_prices::<_, OrmlTokens, _>(total_assets, now) + .calculate_prices::<_, Tokens, _>(total_assets, now) .ok()?; prices.get(index).cloned() } @@ -2042,7 +2237,7 @@ impl_runtime_apis! { let total_assets = pool.reserve.total.saturating_add(nav); pool .tranches - .calculate_prices::(total_assets, now) + .calculate_prices::(total_assets, now) .ok() } @@ -2102,6 +2297,12 @@ impl_runtime_apis! { } } + impl runtime_common::apis::AccountConversionApi for Runtime { + fn conversion_of(location: ::xcm::v3::MultiLocation) -> Option { + AccountConverter::::try_convert(location).ok() + } + } + // Frontier APIs impl fp_rpc::EthereumRuntimeRPCApi for Runtime { fn chain_id() -> u64 { @@ -2228,11 +2429,11 @@ impl_runtime_apis! { fn extrinsic_filter( xts: Vec<::Extrinsic>, - ) -> Vec { + ) -> Vec { xts.into_iter().filter_map(|xt| match xt.0.function { RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), _ => None - }).collect::>() + }).collect::>() } fn elasticity() -> Option { @@ -2243,7 +2444,7 @@ impl_runtime_apis! { } impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { + fn convert_transaction(transaction: EthTransaction) -> ::Extrinsic { UncheckedExtrinsic::new_unsigned( pallet_ethereum::Call::::transact { transaction }.into(), ) diff --git a/runtime/centrifuge/src/migrations.rs b/runtime/centrifuge/src/migrations.rs index 1cc0454009..c3c3631ff7 100644 --- a/runtime/centrifuge/src/migrations.rs +++ b/runtime/centrifuge/src/migrations.rs @@ -9,223 +9,5 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_primitives::Balance; -use cfg_types::tokens::CurrencyId; -use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; -use crate::{LiquidityPoolsPalletIndex, OrmlAssetRegistry, RocksDbWeight, Runtime}; - -pub type UpgradeCentrifuge1020 = ( - asset_registry::CrossChainTransferabilityMigration, - runtime_common::migrations::nuke::Migration, - runtime_common::migrations::nuke::Migration, - asset_registry::RegisterLpEthUSDC, -); - -mod asset_registry { - use cfg_types::{ - tokens as v1, - tokens::{ - lp_eth_usdc_metadata, CustomMetadata, ETHEREUM_MAINNET_CHAIN_ID, ETHEREUM_USDC, - LP_ETH_USDC_CURRENCY_ID, - }, - }; - #[cfg(feature = "try-runtime")] - use frame_support::ensure; - use frame_support::{pallet_prelude::OptionQuery, storage_alias, Twox64Concat}; - use orml_traits::asset_registry::AssetMetadata; - #[cfg(feature = "try-runtime")] - use sp_std::vec::Vec; - - use super::*; - use crate::VERSION; - - /// Migrate all the registered asset's metadata to the new version of - /// `CustomMetadata` which contains a `CrossChainTransferability` property. - /// At this point in time, the `transferability` of Tranche tokens should be - /// set to `CrossChainTransferability::Xcm` and for all other tokens to - /// `CrossChainTransferability::Xcm`, with the exception of - /// `Currency::Staking` tokens which are not registered in the first place. - pub struct CrossChainTransferabilityMigration; - - // The old orml_asset_registry Metadata storage using v0::CustomMetadata - #[storage_alias] - type Metadata = StorageMap< - orml_asset_registry::Pallet, - Twox64Concat, - CurrencyId, - AssetMetadata, - OptionQuery, - >; - - impl OnRuntimeUpgrade for CrossChainTransferabilityMigration { - fn on_runtime_upgrade() -> Weight { - if VERSION.spec_version != 1020 { - return Weight::zero(); - } - - orml_asset_registry::Metadata::::translate( - |asset_id: CurrencyId, old_metadata: AssetMetadata| { - match asset_id { - CurrencyId::Staking(_) => None, - CurrencyId::Tranche(_, _) => Some(to_metadata_v1( - old_metadata, - v1::CrossChainTransferability::LiquidityPools, - )), - _ => Some(to_metadata_v1( - old_metadata.clone(), - v1::CrossChainTransferability::Xcm(old_metadata.additional.xcm), - )), - } - }, - ); - - let n = orml_asset_registry::Metadata::::iter().count() as u64; - ::DbWeight::get().reads_writes(n, n) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - use codec::Encode; - - let old_state: Vec<(CurrencyId, AssetMetadata)> = - Metadata::::iter().collect::>(); - - Ok(old_state.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(old_state_encoded: Vec) -> Result<(), &'static str> { - use codec::Decode; - - let old_state = sp_std::vec::Vec::<( - CurrencyId, - AssetMetadata, - )>::decode(&mut old_state_encoded.as_ref()) - .map_err(|_| "Error decoding pre-upgrade state")?; - - for (asset_id, old_metadata) in old_state { - let new_metadata = OrmlAssetRegistry::metadata(asset_id) - .ok_or_else(|| "New state lost the metadata of an asset")?; - - match asset_id { - CurrencyId::Tranche(_, _) => ensure!(new_metadata == to_metadata_v1( - old_metadata, - v1::CrossChainTransferability::LiquidityPools, - ), "The metadata of a tranche token wasn't just updated by setting `transferability` to `LiquidityPools `"), - _ => ensure!(new_metadata == to_metadata_v1( - old_metadata.clone(), - v1::CrossChainTransferability::Xcm(old_metadata.additional.xcm), - ), "The metadata of a NON tranche token wasn't just updated by setting `transferability` to `Xcm`"), - } - } - - Ok(()) - } - } - - mod v0 { - use cfg_types::xcm::XcmMetadata; - use codec::{Decode, Encode, MaxEncodedLen}; - use scale_info::TypeInfo; - #[cfg(feature = "std")] - use serde::{Deserialize, Serialize}; - - // The `CustomMetadata` type as it was prior to adding the `transferability` - // field and prior to removing the `xcm` field. - #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive( - Clone, - Copy, - Default, - PartialOrd, - Ord, - PartialEq, - Eq, - Debug, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - )] - pub struct CustomMetadata { - pub xcm: XcmMetadata, - pub mintable: bool, - pub permissioned: bool, - pub pool_currency: bool, - } - } - - fn to_metadata_v1( - old: AssetMetadata, - transferability: v1::CrossChainTransferability, - ) -> AssetMetadata { - AssetMetadata { - decimals: old.decimals, - name: old.name, - symbol: old.symbol, - existential_deposit: old.existential_deposit, - location: old.location, - additional: CustomMetadata { - mintable: old.additional.mintable, - permissioned: old.additional.permissioned, - pool_currency: old.additional.pool_currency, - transferability, - }, - } - } - - /// Register the LiquidityPools Wrapped Ethereum USDC - pub struct RegisterLpEthUSDC; - - impl OnRuntimeUpgrade for RegisterLpEthUSDC { - fn on_runtime_upgrade() -> Weight { - use orml_traits::asset_registry::Mutate; - - if OrmlAssetRegistry::metadata(&LP_ETH_USDC_CURRENCY_ID).is_some() { - log::info!("LpEthUSDC is already registered"); - return RocksDbWeight::get().reads(1); - } - - ::register_asset( - Some(LP_ETH_USDC_CURRENCY_ID), - lp_eth_usdc_metadata( - LiquidityPoolsPalletIndex::get(), - ETHEREUM_MAINNET_CHAIN_ID, - ETHEREUM_USDC, - ), - ) - .map_err(|_| log::error!("Failed to register LpEthUSDC")) - .ok(); - - log::info!("RegisterLpEthUSDC: on_runtime_upgrade: completed!"); - RocksDbWeight::get().reads_writes(1, 1) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, &'static str> { - frame_support::ensure!( - OrmlAssetRegistry::metadata(&LP_ETH_USDC_CURRENCY_ID).is_none(), - "LpEthUSDC is already registered; this migration will NOT need to be executed" - ); - - Ok(Default::default()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), &'static str> { - frame_support::ensure!( - OrmlAssetRegistry::metadata(&LP_ETH_USDC_CURRENCY_ID) - == Some(lp_eth_usdc_metadata( - LiquidityPoolsPalletIndex::get(), - ETHEREUM_MAINNET_CHAIN_ID, - ETHEREUM_USDC - )), - "The LpEthUSDC's token metadata does NOT match what we expected it to be" - ); - - log::info!("RegisterLpEthUSDC: post_upgrade: the token metadata looks correct!"); - Ok(()) - } - } -} +pub type UpgradeCentrifuge1021 = (); diff --git a/runtime/centrifuge/src/weights/cumulus_pallet_xcmp_queue.rs b/runtime/centrifuge/src/weights/cumulus_pallet_xcmp_queue.rs index 6be1c9827a..1bc93a4205 100644 --- a/runtime/centrifuge/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/runtime/centrifuge/src/weights/cumulus_pallet_xcmp_queue.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,17 +31,25 @@ use sp_std::marker::PhantomData; /// Weight functions for `cumulus_pallet_xcmp_queue`. pub struct WeightInfo(PhantomData); impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { - // Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Proof Skipped: XcmpQueue QueueConfig (max_values: Some(1), max_size: None, mode: Measured) fn set_config_with_u32() -> Weight { - // Minimum execution time: 11_191 nanoseconds. - Weight::from_ref_time(11_602_000) + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `637` + // Minimum execution time: 8_587 nanoseconds. + Weight::from_parts(9_057_000, 637) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Proof Skipped: XcmpQueue QueueConfig (max_values: Some(1), max_size: None, mode: Measured) fn set_config_with_weight() -> Weight { - // Minimum execution time: 11_061 nanoseconds. - Weight::from_ref_time(11_381_000) + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `637` + // Minimum execution time: 8_636 nanoseconds. + Weight::from_parts(9_037_000, 637) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/frame_system.rs b/runtime/centrifuge/src/weights/frame_system.rs index 7fb42d5a40..ef64d62f1b 100644 --- a/runtime/centrifuge/src/weights/frame_system.rs +++ b/runtime/centrifuge/src/weights/frame_system.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -32,51 +33,75 @@ pub struct WeightInfo(PhantomData); impl frame_system::WeightInfo for WeightInfo { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { - // Minimum execution time: 6_432 nanoseconds. - Weight::from_ref_time(10_227_924) - // Standard Error: 9 - .saturating_add(Weight::from_ref_time(459).saturating_mul(b.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_065 nanoseconds. + Weight::from_ref_time(100_146_976) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(285).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - // Minimum execution time: 20_769 nanoseconds. - Weight::from_ref_time(150_639_763) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_241 nanoseconds. + Weight::from_ref_time(167_579_235) // Standard Error: 5 - .saturating_add(Weight::from_ref_time(1_813).saturating_mul(b.into())) + .saturating_add(Weight::from_ref_time(1_684).saturating_mul(b.into())) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a686561707061676573] (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { - // Minimum execution time: 13_425 nanoseconds. - Weight::from_ref_time(13_866_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `495` + // Minimum execution time: 5_751 nanoseconds. + Weight::from_parts(6_092_000, 495) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - // Minimum execution time: 6_232 nanoseconds. - Weight::from_ref_time(6_442_000) - // Standard Error: 2_194 - .saturating_add(Weight::from_ref_time(963_632).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_965 nanoseconds. + Weight::from_ref_time(3_075_000) + // Standard Error: 1_718 + .saturating_add(Weight::from_ref_time(885_573).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - // Minimum execution time: 6_182 nanoseconds. - Weight::from_ref_time(6_302_000) - // Standard Error: 1_050 - .saturating_add(Weight::from_ref_time(666_222).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_936 nanoseconds. + Weight::from_ref_time(3_055_000) + // Standard Error: 859 + .saturating_add(Weight::from_ref_time(638_231).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - // Minimum execution time: 8_977 nanoseconds. - Weight::from_ref_time(9_157_000) - // Standard Error: 1_133 - .saturating_add(Weight::from_ref_time(1_311_213).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `171 + p * (69 ±0)` + // Estimated: `148 + p * (70 ±0)` + // Minimum execution time: 5_992 nanoseconds. + Weight::from_parts(6_142_000, 148) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(1_283_958).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) } } diff --git a/runtime/centrifuge/src/weights/mod.rs b/runtime/centrifuge/src/weights/mod.rs index 64ade0ed29..12100a50dc 100644 --- a/runtime/centrifuge/src/weights/mod.rs +++ b/runtime/centrifuge/src/weights/mod.rs @@ -25,6 +25,7 @@ pub mod pallet_fees; pub mod pallet_identity; pub mod pallet_interest_accrual; pub mod pallet_keystore; +pub mod pallet_liquidity_rewards; pub mod pallet_loans; pub mod pallet_migration_manager; pub mod pallet_multisig; diff --git a/runtime/centrifuge/src/weights/pallet_anchors.rs b/runtime/centrifuge/src/weights/pallet_anchors.rs index 35f0413acc..0682f97eac 100644 --- a/runtime/centrifuge/src/weights/pallet_anchors.rs +++ b/runtime/centrifuge/src/weights/pallet_anchors.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_anchors` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,247 +31,479 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_anchors`. pub struct WeightInfo(PhantomData); impl pallet_anchors::WeightInfo for WeightInfo { - // Storage: Anchor AnchorEvictDates (r:1 w:0) - // Storage: Anchor PreCommits (r:1 w:1) - // Storage: Fees FeeBalances (r:1 w:0) + /// Storage: Anchor AnchorEvictDates (r:1 w:0) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn pre_commit() -> Weight { - // Minimum execution time: 49_162 nanoseconds. - Weight::from_ref_time(50_223_000) + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `7625` + // Minimum execution time: 34_143 nanoseconds. + Weight::from_parts(34_975_000, 7625) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Timestamp Now (r:1 w:0) - // Storage: Anchor AnchorEvictDates (r:1 w:1) - // Storage: Anchor PreCommits (r:1 w:1) - // Storage: Fees FeeBalances (r:1 w:0) - // Storage: Authorship Author (r:1 w:0) - // Storage: System Digest (r:1 w:0) - // Storage: Anchor LatestAnchorIndex (r:1 w:1) - // Storage: Anchor AnchorIndexes (r:0 w:1) - // Storage: unknown [0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9] (r:0 w:1) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:1 w:1) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Authorship Author (r:1 w:0) + /// Proof: Authorship Author (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: System Digest (r:1 w:0) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Anchor LatestAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:0 w:1) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) + /// Proof Skipped: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) fn commit() -> Weight { - // Minimum execution time: 76_913 nanoseconds. - Weight::from_ref_time(78_116_000) + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `11053` + // Minimum execution time: 64_680 nanoseconds. + Weight::from_parts(66_354_000, 11053) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: Anchor PreCommits (r:100 w:100) + /// Storage: Anchor PreCommits (r:100 w:100) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) fn evict_pre_commits() -> Weight { - // Minimum execution time: 1_731_951 nanoseconds. - Weight::from_ref_time(1_750_024_000) + // Proof Size summary in bytes: + // Measured: `15750` + // Estimated: `259100` + // Minimum execution time: 1_717_384 nanoseconds. + Weight::from_parts(1_729_056_000, 259100) .saturating_add(T::DbWeight::get().reads(100)) .saturating_add(T::DbWeight::get().writes(100)) } - // Storage: Timestamp Now (r:1 w:0) - // Storage: Anchor LatestEvictedDate (r:1 w:1) - // Storage: Anchor EvictedAnchorRoots (r:100 w:100) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000] (r:1 w:0) - // Storage: unknown [0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000] (r:1 w:0) - // Storage: Anchor LatestEvictedAnchorIndex (r:1 w:1) - // Storage: Anchor LatestAnchorIndex (r:1 w:0) - // Storage: Anchor AnchorIndexes (r:100 w:100) - // Storage: Anchor AnchorEvictDates (r:100 w:100) - // Storage: unknown [0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f] (r:0 w:1) - // Storage: unknown [0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704] (r:0 w:1) - // Storage: unknown [0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3] (r:0 w:1) - // Storage: unknown [0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a] (r:0 w:1) - // Storage: unknown [0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c] (r:0 w:1) - // Storage: unknown [0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856] (r:0 w:1) - // Storage: unknown [0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e] (r:0 w:1) - // Storage: unknown [0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff] (r:0 w:1) - // Storage: unknown [0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8] (r:0 w:1) - // Storage: unknown [0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed] (r:0 w:1) - // Storage: unknown [0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f] (r:0 w:1) - // Storage: unknown [0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464] (r:0 w:1) - // Storage: unknown [0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde] (r:0 w:1) - // Storage: unknown [0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a] (r:0 w:1) - // Storage: unknown [0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380] (r:0 w:1) - // Storage: unknown [0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84] (r:0 w:1) - // Storage: unknown [0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f] (r:0 w:1) - // Storage: unknown [0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5] (r:0 w:1) - // Storage: unknown [0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf] (r:0 w:1) - // Storage: unknown [0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea] (r:0 w:1) - // Storage: unknown [0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2] (r:0 w:1) - // Storage: unknown [0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e] (r:0 w:1) - // Storage: unknown [0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df] (r:0 w:1) - // Storage: unknown [0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0] (r:0 w:1) - // Storage: unknown [0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b] (r:0 w:1) - // Storage: unknown [0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b] (r:0 w:1) - // Storage: unknown [0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9] (r:0 w:1) - // Storage: unknown [0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775] (r:0 w:1) - // Storage: unknown [0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906] (r:0 w:1) - // Storage: unknown [0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5] (r:0 w:1) - // Storage: unknown [0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0] (r:0 w:1) - // Storage: unknown [0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17] (r:0 w:1) - // Storage: unknown [0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8] (r:0 w:1) - // Storage: unknown [0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644] (r:0 w:1) - // Storage: unknown [0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90] (r:0 w:1) - // Storage: unknown [0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9] (r:0 w:1) - // Storage: unknown [0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287] (r:0 w:1) - // Storage: unknown [0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0] (r:0 w:1) - // Storage: unknown [0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403] (r:0 w:1) - // Storage: unknown [0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2] (r:0 w:1) - // Storage: unknown [0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044] (r:0 w:1) - // Storage: unknown [0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec] (r:0 w:1) - // Storage: unknown [0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e] (r:0 w:1) - // Storage: unknown [0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1] (r:0 w:1) - // Storage: unknown [0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55] (r:0 w:1) - // Storage: unknown [0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0] (r:0 w:1) - // Storage: unknown [0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820] (r:0 w:1) - // Storage: unknown [0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7] (r:0 w:1) - // Storage: unknown [0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329] (r:0 w:1) - // Storage: unknown [0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0] (r:0 w:1) - // Storage: unknown [0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0] (r:0 w:1) - // Storage: unknown [0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256] (r:0 w:1) - // Storage: unknown [0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773] (r:0 w:1) - // Storage: unknown [0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826] (r:0 w:1) - // Storage: unknown [0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6] (r:0 w:1) - // Storage: unknown [0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc] (r:0 w:1) - // Storage: unknown [0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75] (r:0 w:1) - // Storage: unknown [0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5] (r:0 w:1) - // Storage: unknown [0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17] (r:0 w:1) - // Storage: unknown [0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce] (r:0 w:1) - // Storage: unknown [0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956] (r:0 w:1) - // Storage: unknown [0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c] (r:0 w:1) - // Storage: unknown [0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1] (r:0 w:1) - // Storage: unknown [0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb] (r:0 w:1) - // Storage: unknown [0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56] (r:0 w:1) - // Storage: unknown [0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78] (r:0 w:1) - // Storage: unknown [0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987] (r:0 w:1) - // Storage: unknown [0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013] (r:0 w:1) - // Storage: unknown [0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d] (r:0 w:1) - // Storage: unknown [0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58] (r:0 w:1) - // Storage: unknown [0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad] (r:0 w:1) - // Storage: unknown [0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136] (r:0 w:1) - // Storage: unknown [0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb] (r:0 w:1) - // Storage: unknown [0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0] (r:0 w:1) - // Storage: unknown [0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561] (r:0 w:1) - // Storage: unknown [0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd] (r:0 w:1) - // Storage: unknown [0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a] (r:0 w:1) - // Storage: unknown [0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b] (r:0 w:1) - // Storage: unknown [0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2] (r:0 w:1) - // Storage: unknown [0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5] (r:0 w:1) - // Storage: unknown [0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c] (r:0 w:1) - // Storage: unknown [0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362] (r:0 w:1) - // Storage: unknown [0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc] (r:0 w:1) - // Storage: unknown [0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7] (r:0 w:1) - // Storage: unknown [0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58] (r:0 w:1) - // Storage: unknown [0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f] (r:0 w:1) - // Storage: unknown [0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171] (r:0 w:1) - // Storage: unknown [0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63] (r:0 w:1) - // Storage: unknown [0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b] (r:0 w:1) - // Storage: unknown [0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a] (r:0 w:1) - // Storage: unknown [0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f] (r:0 w:1) - // Storage: unknown [0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b] (r:0 w:1) - // Storage: unknown [0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a] (r:0 w:1) - // Storage: unknown [0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e] (r:0 w:1) - // Storage: unknown [0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1] (r:0 w:1) - // Storage: unknown [0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8] (r:0 w:1) - // Storage: unknown [0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c] (r:0 w:1) - // Storage: unknown [0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48] (r:0 w:1) - // Storage: unknown [0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b] (r:0 w:1) - // Storage: unknown [0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312] (r:0 w:1) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestEvictedDate (r:1 w:1) + /// Proof: Anchor LatestEvictedDate (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Anchor EvictedAnchorRoots (r:100 w:100) + /// Proof: Anchor EvictedAnchorRoots (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Storage: Anchor LatestEvictedAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestEvictedAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestAnchorIndex (r:1 w:0) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:100 w:100) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:100 w:100) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Proof Skipped: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Storage: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Proof Skipped: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Storage: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Proof Skipped: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Storage: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Proof Skipped: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Storage: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Proof Skipped: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Storage: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Proof Skipped: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Storage: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Proof Skipped: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Storage: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Proof Skipped: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Storage: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Proof Skipped: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Storage: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Proof Skipped: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Storage: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Proof Skipped: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Storage: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Proof Skipped: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Storage: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Proof Skipped: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Storage: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Proof Skipped: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Storage: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Proof Skipped: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Storage: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Proof Skipped: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Storage: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Proof Skipped: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Storage: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Proof Skipped: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Storage: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Proof Skipped: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Storage: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Proof Skipped: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Storage: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Proof Skipped: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Storage: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Proof Skipped: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Storage: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Proof Skipped: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Storage: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Proof Skipped: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Storage: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Proof Skipped: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Storage: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Proof Skipped: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Storage: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Proof Skipped: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Storage: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Proof Skipped: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Storage: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Proof Skipped: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Storage: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Proof Skipped: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Storage: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Proof Skipped: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Storage: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Proof Skipped: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Storage: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Proof Skipped: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Storage: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Proof Skipped: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Storage: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Proof Skipped: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Storage: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Proof Skipped: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Storage: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Proof Skipped: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Storage: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Proof Skipped: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Storage: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Proof Skipped: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Storage: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Proof Skipped: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Storage: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Proof Skipped: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Storage: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Proof Skipped: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Storage: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Proof Skipped: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Storage: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Proof Skipped: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Storage: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Proof Skipped: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Storage: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Storage: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Proof Skipped: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Storage: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Proof Skipped: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Storage: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Proof Skipped: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Storage: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Proof Skipped: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Storage: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Storage: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Proof Skipped: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Storage: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Proof Skipped: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Storage: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Proof Skipped: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Storage: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Proof Skipped: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Storage: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Proof Skipped: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Storage: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Proof Skipped: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Storage: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Proof Skipped: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Storage: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Proof Skipped: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Storage: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Proof Skipped: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Storage: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Proof Skipped: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Storage: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Proof Skipped: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Storage: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Proof Skipped: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Storage: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Proof Skipped: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Storage: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Proof Skipped: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Storage: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Proof Skipped: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Storage: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Proof Skipped: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Storage: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Proof Skipped: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Storage: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Proof Skipped: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Storage: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Proof Skipped: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Storage: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Proof Skipped: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Storage: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Proof Skipped: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Storage: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Proof Skipped: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Storage: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Proof Skipped: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Storage: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Proof Skipped: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Storage: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Proof Skipped: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Storage: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Proof Skipped: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Storage: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Proof Skipped: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Storage: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Proof Skipped: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Storage: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Proof Skipped: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Storage: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Proof Skipped: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Storage: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Proof Skipped: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Storage: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Proof Skipped: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Storage: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Proof Skipped: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Storage: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Proof Skipped: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Storage: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Proof Skipped: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Storage: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Proof Skipped: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Storage: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Proof Skipped: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Storage: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Proof Skipped: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Storage: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Proof Skipped: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Storage: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Proof Skipped: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Storage: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Proof Skipped: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Storage: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Proof Skipped: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Storage: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Proof Skipped: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Storage: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Proof Skipped: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Storage: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Proof Skipped: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Storage: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Proof Skipped: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Storage: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Proof Skipped: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Storage: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Proof Skipped: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Storage: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) + /// Proof Skipped: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) fn evict_anchors() -> Weight { - // Minimum execution time: 1_914_802 nanoseconds. - Weight::from_ref_time(1_933_317_000) + // Proof Size summary in bytes: + // Measured: `18358` + // Estimated: `4680108` + // Minimum execution time: 1_875_548 nanoseconds. + Weight::from_parts(1_894_002_000, 4680108) .saturating_add(T::DbWeight::get().reads(404)) .saturating_add(T::DbWeight::get().writes(402)) } diff --git a/runtime/centrifuge/src/weights/pallet_balances.rs b/runtime/centrifuge/src/weights/pallet_balances.rs index d4aed4e57c..446933fb3c 100644 --- a/runtime/centrifuge/src/weights/pallet_balances.rs +++ b/runtime/centrifuge/src/weights/pallet_balances.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,52 +31,80 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 69_269 nanoseconds. - Weight::from_ref_time(70_702_000) + // Proof Size summary in bytes: + // Measured: `1829` + // Estimated: `2603` + // Minimum execution time: 73_337 nanoseconds. + Weight::from_parts(74_117_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // Minimum execution time: 51_015 nanoseconds. - Weight::from_ref_time(51_546_000) + // Proof Size summary in bytes: + // Measured: `1538` + // Estimated: `2603` + // Minimum execution time: 52_207 nanoseconds. + Weight::from_parts(53_409_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { - // Minimum execution time: 37_831 nanoseconds. - Weight::from_ref_time(39_314_000) + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `2603` + // Minimum execution time: 39_463 nanoseconds. + Weight::from_parts(40_666_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { - // Minimum execution time: 42_088 nanoseconds. - Weight::from_ref_time(43_822_000) + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `2603` + // Minimum execution time: 45_765 nanoseconds. + Weight::from_parts(46_747_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:2 w:2) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // Minimum execution time: 69_089 nanoseconds. - Weight::from_ref_time(70_571_000) + // Proof Size summary in bytes: + // Measured: `1829` + // Estimated: `5206` + // Minimum execution time: 73_607 nanoseconds. + Weight::from_parts(74_519_000, 5206) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { - // Minimum execution time: 59_671 nanoseconds. - Weight::from_ref_time(60_993_000) + // Proof Size summary in bytes: + // Measured: `1538` + // Estimated: `2603` + // Minimum execution time: 61_054 nanoseconds. + Weight::from_parts(62_206_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { - // Minimum execution time: 31_469 nanoseconds. - Weight::from_ref_time(32_080_000) + // Proof Size summary in bytes: + // Measured: `1572` + // Estimated: `2603` + // Minimum execution time: 33_031 nanoseconds. + Weight::from_parts(34_183_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_block_rewards.rs b/runtime/centrifuge/src/weights/pallet_block_rewards.rs index f0edb8512b..735dd95ea1 100644 --- a/runtime/centrifuge/src/weights/pallet_block_rewards.rs +++ b/runtime/centrifuge/src/weights/pallet_block_rewards.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_block_rewards` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,29 +31,46 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_block_rewards`. pub struct WeightInfo(PhantomData); impl pallet_block_rewards::WeightInfo for WeightInfo { - // Storage: BlockRewardsBase Currency (r:1 w:0) - // Storage: BlockRewardsBase Group (r:1 w:0) - // Storage: BlockRewardsBase StakeAccount (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: BlockRewardsBase Currency (r:1 w:0) + /// Proof: BlockRewardsBase Currency (max_values: None, max_size: Some(79), added: 2554, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase Group (r:1 w:0) + /// Proof: BlockRewardsBase Group (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase StakeAccount (r:1 w:1) + /// Proof: BlockRewardsBase StakeAccount (max_values: None, max_size: Some(123), added: 2598, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_reward() -> Weight { - // Minimum execution time: 73_037 nanoseconds. - Weight::from_ref_time(74_118_000) + // Proof Size summary in bytes: + // Measured: `678` + // Estimated: `12885` + // Minimum execution time: 58_770 nanoseconds. + Weight::from_parts(60_482_000, 12885) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) - // Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_collator_reward() -> Weight { - // Minimum execution time: 15_910 nanoseconds. - Weight::from_ref_time(16_321_000) + // Proof Size summary in bytes: + // Measured: `138` + // Estimated: `3115` + // Minimum execution time: 12_142 nanoseconds. + Weight::from_parts(12_674_000, 3115) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) - // Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_total_reward() -> Weight { - // Minimum execution time: 14_707 nanoseconds. - Weight::from_ref_time(15_509_000) + // Proof Size summary in bytes: + // Measured: `97` + // Estimated: `3115` + // Minimum execution time: 11_201 nanoseconds. + Weight::from_parts(11_511_000, 3115) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_collator_allowlist.rs b/runtime/centrifuge/src/weights/pallet_collator_allowlist.rs index 6ccd80d8d1..4fd399153f 100644 --- a/runtime/centrifuge/src/weights/pallet_collator_allowlist.rs +++ b/runtime/centrifuge/src/weights/pallet_collator_allowlist.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_collator_allowlist` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,18 +31,27 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collator_allowlist`. pub struct WeightInfo(PhantomData); impl pallet_collator_allowlist::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn add() -> Weight { - // Minimum execution time: 34_965 nanoseconds. - Weight::from_ref_time(35_987_000) + // Proof Size summary in bytes: + // Measured: `490` + // Estimated: `5472` + // Minimum execution time: 25_557 nanoseconds. + Weight::from_parts(26_329_000, 5472) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn remove() -> Weight { - // Minimum execution time: 27_502 nanoseconds. - Weight::from_ref_time(28_193_000) + // Proof Size summary in bytes: + // Measured: `166` + // Estimated: `2507` + // Minimum execution time: 18_975 nanoseconds. + Weight::from_parts(19_687_000, 2507) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_collator_selection.rs b/runtime/centrifuge/src/weights/pallet_collator_selection.rs index bdf81848b7..30988e15a2 100644 --- a/runtime/centrifuge/src/weights/pallet_collator_selection.rs +++ b/runtime/centrifuge/src/weights/pallet_collator_selection.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,86 +31,133 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - // Storage: CollatorAllowlist Allowlist (r:1 w:0) - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Storage: CollatorAllowlist Allowlist (r:100 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:100 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) /// The range of component `b` is `[1, 100]`. /// The range of component `b` is `[1, 100]`. fn set_invulnerables(b: u32, ) -> Weight { - // Minimum execution time: 35_777 nanoseconds. - Weight::from_ref_time(35_179_588) - // Standard Error: 2_935 - .saturating_add(Weight::from_ref_time(5_695_889).saturating_mul(b.into())) + // Proof Size summary in bytes: + // Measured: `400 + b * (144 ±0)` + // Estimated: `397 + b * (5127 ±0)` + // Minimum execution time: 25_277 nanoseconds. + Weight::from_parts(23_693_174, 397) + // Standard Error: 4_832 + .saturating_add(Weight::from_ref_time(5_694_808).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(5127).saturating_mul(b.into())) } - // Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_desired_candidates() -> Weight { - // Minimum execution time: 23_654 nanoseconds. - Weight::from_ref_time(24_506_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 14_998 nanoseconds. + Weight::from_ref_time(15_889_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_candidacy_bond() -> Weight { - // Minimum execution time: 19_827 nanoseconds. - Weight::from_ref_time(20_399_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_639 nanoseconds. + Weight::from_ref_time(11_251_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection DesiredCandidates (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: CollatorAllowlist Allowlist (r:1 w:0) - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection CandidacyBond (r:1 w:0) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection DesiredCandidates (r:1 w:0) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: CollatorAllowlist Allowlist (r:1 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection CandidacyBond (r:1 w:0) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) /// The range of component `c` is `[1, 99]`. /// The range of component `c` is `[1, 99]`. fn register_as_candidate(c: u32, ) -> Weight { - // Minimum execution time: 74_439 nanoseconds. - Weight::from_ref_time(79_785_077) - // Standard Error: 1_097 - .saturating_add(Weight::from_ref_time(196_379).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `1187 + c * (52 ±0)` + // Estimated: `16122 + c * (53 ±0)` + // Minimum execution time: 59_931 nanoseconds. + Weight::from_parts(62_764_209, 16122) + // Standard Error: 665 + .saturating_add(Weight::from_ref_time(124_788).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(53).saturating_mul(c.into())) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) /// The range of component `c` is `[6, 100]`. /// The range of component `c` is `[6, 100]`. fn leave_intent(c: u32, ) -> Weight { - // Minimum execution time: 50_785 nanoseconds. - Weight::from_ref_time(52_270_125) - // Standard Error: 1_251 - .saturating_add(Weight::from_ref_time(169_169).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `430 + c * (49 ±0)` + // Estimated: `5297` + // Minimum execution time: 37_239 nanoseconds. + Weight::from_parts(39_032_360, 5297) + // Standard Error: 1_038 + .saturating_add(Weight::from_ref_time(130_212).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:2 w:2) - // Storage: System BlockWeight (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { - // Minimum execution time: 52_007 nanoseconds. - Weight::from_ref_time(52_949_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `5749` + // Minimum execution time: 42_960 nanoseconds. + Weight::from_parts(44_002_000, 5749) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:100 w:1) - // Storage: System Account (r:1 w:1) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: System BlockWeight (r:1 w:1) + /// Storage: CollatorSelection Candidates (r:1 w:0) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:100 w:0) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: System Account (r:95 w:95) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. /// The range of component `c` is `[1, 100]`. /// The range of component `r` is `[1, 100]`. /// The range of component `c` is `[1, 100]`. - fn new_session(_r: u32, c: u32, ) -> Weight { - // Minimum execution time: 31_308 nanoseconds. - Weight::from_ref_time(31_849_000) - // Standard Error: 218_029 - .saturating_add(Weight::from_ref_time(16_477_897).saturating_mul(c.into())) + fn new_session(r: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2629 + r * (147 ±0) + c * (97 ±0)` + // Estimated: `909314980955027 + r * (2597 ±4) + c * (2519 ±0)` + // Minimum execution time: 25_317 nanoseconds. + Weight::from_parts(25_678_000, 909314980955027) + // Standard Error: 208_679 + .saturating_add(Weight::from_ref_time(15_673_406).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(2519).saturating_mul(c.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_collective.rs b/runtime/centrifuge/src/weights/pallet_collective.rs index 883fe6ddce..bbbe6f0490 100644 --- a/runtime/centrifuge/src/weights/pallet_collective.rs +++ b/runtime/centrifuge/src/weights/pallet_collective.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,163 +31,244 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collective`. pub struct WeightInfo(PhantomData); impl pallet_collective::WeightInfo for WeightInfo { - // Storage: Council Members (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Prime (r:0 w:1) - // Storage: Council Voting (r:100 w:100) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // Minimum execution time: 24_485 nanoseconds. - Weight::from_ref_time(24_616_000) - // Standard Error: 58_562 - .saturating_add(Weight::from_ref_time(4_407_657).saturating_mul(m.into())) - // Standard Error: 58_562 - .saturating_add(Weight::from_ref_time(8_316_235).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` + // Estimated: `16190 + m * (7809 ±23) + p * (10238 ±23)` + // Minimum execution time: 22_181 nanoseconds. + Weight::from_parts(22_382_000, 16190) + // Standard Error: 64_236 + .saturating_add(Weight::from_ref_time(5_017_878).saturating_mul(m.into())) + // Standard Error: 64_236 + .saturating_add(Weight::from_ref_time(8_816_080).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 31_589 nanoseconds. - Weight::from_ref_time(30_874_178) - // Standard Error: 45 - .saturating_add(Weight::from_ref_time(2_206).saturating_mul(b.into())) - // Standard Error: 473 - .saturating_add(Weight::from_ref_time(23_752).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `631 + m * (32 ±0)` + // Minimum execution time: 22_962 nanoseconds. + Weight::from_parts(26_779_786, 631) + // Standard Error: 430 + .saturating_add(Weight::from_ref_time(1_344).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:0) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // Minimum execution time: 35_667 nanoseconds. - Weight::from_ref_time(34_732_846) - // Standard Error: 58 - .saturating_add(Weight::from_ref_time(1_893).saturating_mul(b.into())) - // Standard Error: 604 - .saturating_add(Weight::from_ref_time(34_862).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `3242 + m * (64 ±0)` + // Minimum execution time: 27_642 nanoseconds. + Weight::from_parts(26_433_668, 3242) + // Standard Error: 121 + .saturating_add(Weight::from_ref_time(1_876).saturating_mul(b.into())) + // Standard Error: 1_251 + .saturating_add(Weight::from_ref_time(34_391).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalCount (r:1 w:1) - // Storage: Council Voting (r:0 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 45_404 nanoseconds. - Weight::from_ref_time(44_764_872) - // Standard Error: 140 - .saturating_add(Weight::from_ref_time(3_717).saturating_mul(b.into())) - // Standard Error: 1_465 - .saturating_add(Weight::from_ref_time(35_214).saturating_mul(m.into())) - // Standard Error: 1_446 - .saturating_add(Weight::from_ref_time(226_466).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `457 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `5860 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 34_604 nanoseconds. + Weight::from_parts(34_796_534, 5860) + // Standard Error: 105 + .saturating_add(Weight::from_ref_time(2_792).saturating_mul(b.into())) + // Standard Error: 1_104 + .saturating_add(Weight::from_ref_time(30_927).saturating_mul(m.into())) + // Standard Error: 1_090 + .saturating_add(Weight::from_ref_time(196_263).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council Voting (r:1 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 43_742 nanoseconds. - Weight::from_ref_time(45_142_583) - // Standard Error: 1_113 - .saturating_add(Weight::from_ref_time(59_758).saturating_mul(m.into())) + // Proof Size summary in bytes: + // Measured: `907 + m * (64 ±0)` + // Estimated: `4782 + m * (128 ±0)` + // Minimum execution time: 30_346 nanoseconds. + Weight::from_parts(31_236_497, 4782) + // Standard Error: 831 + .saturating_add(Weight::from_ref_time(48_491).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 47_068 nanoseconds. - Weight::from_ref_time(48_902_826) - // Standard Error: 1_444 - .saturating_add(Weight::from_ref_time(39_869).saturating_mul(m.into())) - // Standard Error: 1_408 - .saturating_add(Weight::from_ref_time(208_066).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `527 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `5497 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 38_802 nanoseconds. + Weight::from_parts(39_018_269, 5497) + // Standard Error: 1_122 + .saturating_add(Weight::from_ref_time(34_336).saturating_mul(m.into())) + // Standard Error: 1_094 + .saturating_add(Weight::from_ref_time(178_059).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 64_590 nanoseconds. - Weight::from_ref_time(65_299_240) - // Standard Error: 144 - .saturating_add(Weight::from_ref_time(2_884).saturating_mul(b.into())) - // Standard Error: 1_531 - .saturating_add(Weight::from_ref_time(25_857).saturating_mul(m.into())) - // Standard Error: 1_493 - .saturating_add(Weight::from_ref_time(232_292).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `863 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `8768 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 55_484 nanoseconds. + Weight::from_parts(56_878_974, 8768) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(3_290).saturating_mul(b.into())) + // Standard Error: 3_027 + .saturating_add(Weight::from_ref_time(8_523).saturating_mul(m.into())) + // Standard Error: 2_950 + .saturating_add(Weight::from_ref_time(227_600).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Prime (r:1 w:0) - // Storage: Council Proposals (r:1 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 51_536 nanoseconds. - Weight::from_ref_time(51_764_107) - // Standard Error: 1_256 - .saturating_add(Weight::from_ref_time(47_496).saturating_mul(m.into())) - // Standard Error: 1_225 - .saturating_add(Weight::from_ref_time(209_085).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `547 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `6600 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 41_838 nanoseconds. + Weight::from_parts(41_889_250, 6600) + // Standard Error: 1_132 + .saturating_add(Weight::from_ref_time(40_912).saturating_mul(m.into())) + // Standard Error: 1_104 + .saturating_add(Weight::from_ref_time(183_713).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Voting (r:1 w:1) - // Storage: Council Members (r:1 w:0) - // Storage: Council Prime (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:1) - // Storage: Council Proposals (r:1 w:1) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 66_484 nanoseconds. - Weight::from_ref_time(68_467_538) - // Standard Error: 156 - .saturating_add(Weight::from_ref_time(2_633).saturating_mul(b.into())) - // Standard Error: 1_652 - .saturating_add(Weight::from_ref_time(27_015).saturating_mul(m.into())) - // Standard Error: 1_611 - .saturating_add(Weight::from_ref_time(238_091).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `883 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `10070 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 59_231 nanoseconds. + Weight::from_parts(60_514_207, 10070) + // Standard Error: 166 + .saturating_add(Weight::from_ref_time(2_880).saturating_mul(b.into())) + // Standard Error: 1_764 + .saturating_add(Weight::from_ref_time(33_489).saturating_mul(m.into())) + // Standard Error: 1_719 + .saturating_add(Weight::from_ref_time(221_396).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) } - // Storage: Council Proposals (r:1 w:1) - // Storage: Council Voting (r:0 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // Minimum execution time: 30_586 nanoseconds. - Weight::from_ref_time(33_372_557) - // Standard Error: 1_333 - .saturating_add(Weight::from_ref_time(215_940).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `292 + p * (32 ±0)` + // Estimated: `1371 + p * (96 ±0)` + // Minimum execution time: 22_161 nanoseconds. + Weight::from_parts(23_967_563, 1371) + // Standard Error: 867 + .saturating_add(Weight::from_ref_time(171_643).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_crowdloan_claim.rs b/runtime/centrifuge/src/weights/pallet_crowdloan_claim.rs index 6399d54d64..00b4fc15bc 100644 --- a/runtime/centrifuge/src/weights/pallet_crowdloan_claim.rs +++ b/runtime/centrifuge/src/weights/pallet_crowdloan_claim.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_crowdloan_claim` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,98 +31,170 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_crowdloan_claim`. pub struct WeightInfo(PhantomData); impl pallet_crowdloan_claim::WeightInfo for WeightInfo { - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ed25519() -> Weight { - // Minimum execution time: 224_569 nanoseconds. - Weight::from_ref_time(226_984_000) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `17661` + // Minimum execution time: 210_352 nanoseconds. + Weight::from_parts(213_026_000, 17661) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_sr25519() -> Weight { - // Minimum execution time: 227_244 nanoseconds. - Weight::from_ref_time(229_959_000) + // Proof Size summary in bytes: + // Measured: `658` + // Estimated: `17661` + // Minimum execution time: 213_567 nanoseconds. + Weight::from_parts(215_962_000, 17661) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:0) - // Storage: CrowdloanClaim LeaseStart (r:1 w:0) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:0) - // Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) - // Storage: CrowdloanClaim Contributions (r:1 w:0) - // Storage: CrowdloanReward VestingStart (r:1 w:0) - // Storage: CrowdloanReward VestingPeriod (r:1 w:0) - // Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ecdsa() -> Weight { - // Minimum execution time: 206_976 nanoseconds. - Weight::from_ref_time(209_270_000) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `17661` + // Minimum execution time: 194_302 nanoseconds. + Weight::from_parts(196_496_000, 17661) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: CrowdloanClaim CurrIndex (r:1 w:1) - // Storage: CrowdloanClaim LeaseStart (r:1 w:1) - // Storage: CrowdloanClaim LeasePeriod (r:1 w:1) - // Storage: CrowdloanClaim PrevIndex (r:1 w:0) - // Storage: CrowdloanClaim Contributions (r:0 w:1) - // Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) - // Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Storage: CrowdloanClaim CurrIndex (r:1 w:1) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim PrevIndex (r:1 w:0) + /// Proof: CrowdloanClaim PrevIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - // Minimum execution time: 31_839 nanoseconds. - Weight::from_ref_time(32_581_000) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1996` + // Minimum execution time: 24_125 nanoseconds. + Weight::from_parts(24_927_000, 1996) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: CrowdloanClaim LeaseStart (r:0 w:1) + /// Storage: CrowdloanClaim LeaseStart (r:0 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_start() -> Weight { - // Minimum execution time: 19_626 nanoseconds. - Weight::from_ref_time(20_218_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_511 nanoseconds. + Weight::from_ref_time(11_992_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim LeasePeriod (r:0 w:1) + /// Storage: CrowdloanClaim LeasePeriod (r:0 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_period() -> Weight { - // Minimum execution time: 20_017 nanoseconds. - Weight::from_ref_time(20_739_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_762 nanoseconds. + Weight::from_ref_time(12_032_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) fn set_contributions_root() -> Weight { - // Minimum execution time: 20_428 nanoseconds. - Weight::from_ref_time(21_340_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_453 nanoseconds. + Weight::from_ref_time(12_974_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_locked_at() -> Weight { - // Minimum execution time: 20_137 nanoseconds. - Weight::from_ref_time(20_608_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_641 nanoseconds. + Weight::from_ref_time(11_982_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_crowdloan_trie_index() -> Weight { - // Minimum execution time: 20_037 nanoseconds. - Weight::from_ref_time(20_759_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_421 nanoseconds. + Weight::from_ref_time(11_832_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/centrifuge/src/weights/pallet_crowdloan_reward.rs b/runtime/centrifuge/src/weights/pallet_crowdloan_reward.rs index 36129ba54c..0e975097ee 100644 --- a/runtime/centrifuge/src/weights/pallet_crowdloan_reward.rs +++ b/runtime/centrifuge/src/weights/pallet_crowdloan_reward.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_crowdloan_reward` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,30 +31,48 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_crowdloan_reward`. pub struct WeightInfo(PhantomData); impl pallet_crowdloan_reward::WeightInfo for WeightInfo { - // Storage: CrowdloanReward VestingStart (r:0 w:1) - // Storage: CrowdloanReward VestingPeriod (r:0 w:1) - // Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - // Minimum execution time: 21_761 nanoseconds. - Weight::from_ref_time(22_172_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_365 nanoseconds. + Weight::from_ref_time(14_106_000) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_start() -> Weight { - // Minimum execution time: 19_887 nanoseconds. - Weight::from_ref_time(20_418_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_331 nanoseconds. + Weight::from_ref_time(11_852_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_period() -> Weight { - // Minimum execution time: 19_476 nanoseconds. - Weight::from_ref_time(20_218_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_361 nanoseconds. + Weight::from_ref_time(11_772_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_direct_payout_ratio() -> Weight { - // Minimum execution time: 19_827 nanoseconds. - Weight::from_ref_time(20_588_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_681 nanoseconds. + Weight::from_ref_time(11_972_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/centrifuge/src/weights/pallet_democracy.rs b/runtime/centrifuge/src/weights/pallet_democracy.rs index eda827c8e0..1d2b2cb9e6 100644 --- a/runtime/centrifuge/src/weights/pallet_democracy.rs +++ b/runtime/centrifuge/src/weights/pallet_democracy.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_democracy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,218 +31,345 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_democracy`. pub struct WeightInfo(PhantomData); impl pallet_democracy::WeightInfo for WeightInfo { - // Storage: Democracy PublicPropCount (r:1 w:1) - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) - // Storage: Democracy DepositOf (r:0 w:1) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { - // Minimum execution time: 66_764 nanoseconds. - Weight::from_ref_time(68_658_000) + // Proof Size summary in bytes: + // Measured: `4864` + // Estimated: `23409` + // Minimum execution time: 50_995 nanoseconds. + Weight::from_parts(52_327_000, 23409) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy DepositOf (r:1 w:1) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { - // Minimum execution time: 60_504 nanoseconds. - Weight::from_ref_time(62_256_000) + // Proof Size summary in bytes: + // Measured: `3620` + // Estimated: `5705` + // Minimum execution time: 44_533 nanoseconds. + Weight::from_parts(45_645_000, 5705) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { - // Minimum execution time: 77_214 nanoseconds. - Weight::from_ref_time(78_446_000) + // Proof Size summary in bytes: + // Measured: `3517` + // Estimated: `12720` + // Minimum execution time: 57_527 nanoseconds. + Weight::from_parts(58_709_000, 12720) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // Minimum execution time: 77_524 nanoseconds. - Weight::from_ref_time(79_017_000) + // Proof Size summary in bytes: + // Measured: `3539` + // Estimated: `12720` + // Minimum execution time: 57_396 nanoseconds. + Weight::from_parts(58_359_000, 12720) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy Cancellations (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { - // Minimum execution time: 32_871 nanoseconds. - Weight::from_ref_time(33_693_000) + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `5184` + // Minimum execution time: 26_299 nanoseconds. + Weight::from_parts(26_760_000, 5184) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy Blacklist (r:0 w:1) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { - // Minimum execution time: 123_471 nanoseconds. - Weight::from_ref_time(126_487_000) + // Proof Size summary in bytes: + // Measured: `6362` + // Estimated: `31411` + // Minimum execution time: 113_601 nanoseconds. + Weight::from_parts(115_816_000, 31411) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { - // Minimum execution time: 25_046 nanoseconds. - Weight::from_ref_time(25_938_000) + // Proof Size summary in bytes: + // Measured: `3448` + // Estimated: `6340` + // Minimum execution time: 18_725 nanoseconds. + Weight::from_parts(20_679_000, 6340) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:0 w:1) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { - // Minimum execution time: 8_006 nanoseconds. - Weight::from_ref_time(8_336_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_950 nanoseconds. + Weight::from_ref_time(5_360_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:0 w:1) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { - // Minimum execution time: 7_734 nanoseconds. - Weight::from_ref_time(8_156_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_109 nanoseconds. + Weight::from_ref_time(5_400_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { - // Minimum execution time: 32_550 nanoseconds. - Weight::from_ref_time(33_783_000) + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `1126` + // Minimum execution time: 24_536 nanoseconds. + Weight::from_parts(25_127_000, 1126) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy NextExternal (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:1) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn veto_external() -> Weight { - // Minimum execution time: 39_123 nanoseconds. - Weight::from_ref_time(40_575_000) + // Proof Size summary in bytes: + // Measured: `3477` + // Estimated: `6340` + // Minimum execution time: 29_765 nanoseconds. + Weight::from_parts(30_476_000, 6340) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { - // Minimum execution time: 104_255 nanoseconds. - Weight::from_ref_time(107_320_000) + // Proof Size summary in bytes: + // Measured: `6241` + // Estimated: `28108` + // Minimum execution time: 93_905 nanoseconds. + Weight::from_parts(95_948_000, 28108) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { - // Minimum execution time: 21_370 nanoseconds. - Weight::from_ref_time(22_051_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_994 nanoseconds. + Weight::from_ref_time(13_435_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy LowestUnbaked (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - // Minimum execution time: 10_019 nanoseconds. - Weight::from_ref_time(13_166_365) - // Standard Error: 4_806 - .saturating_add(Weight::from_ref_time(3_521_921).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `998 + r * (2676 ±0)` + // Minimum execution time: 9_849 nanoseconds. + Weight::from_parts(11_673_837, 998) + // Standard Error: 6_204 + .saturating_add(Weight::from_ref_time(3_796_302).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy LowestUnbaked (r:1 w:1) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy LastTabledWasExternal (r:1 w:0) - // Storage: Democracy NextExternal (r:1 w:0) - // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // Minimum execution time: 14_447 nanoseconds. - Weight::from_ref_time(17_275_277) - // Standard Error: 4_751 - .saturating_add(Weight::from_ref_time(3_523_937).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `19318 + r * (2676 ±0)` + // Minimum execution time: 14_327 nanoseconds. + Weight::from_parts(16_751_056, 19318) + // Standard Error: 5_860 + .saturating_add(Weight::from_ref_time(3_786_297).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Balances Locks (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - // Minimum execution time: 65_132 nanoseconds. - Weight::from_ref_time(70_440_866) - // Standard Error: 7_512 - .saturating_add(Weight::from_ref_time(5_112_134).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `914 + r * (139 ±0)` + // Estimated: `22584 + r * (2676 ±0)` + // Minimum execution time: 48_801 nanoseconds. + Weight::from_parts(53_950_712, 22584) + // Standard Error: 7_320 + .saturating_add(Weight::from_ref_time(4_820_964).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - // Minimum execution time: 38_141 nanoseconds. - Weight::from_ref_time(40_072_492) - // Standard Error: 6_052 - .saturating_add(Weight::from_ref_time(5_051_009).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `547 + r * (139 ±0)` + // Estimated: `12540 + r * (2676 ±0)` + // Minimum execution time: 28_513 nanoseconds. + Weight::from_parts(28_322_604, 12540) + // Standard Error: 8_047 + .saturating_add(Weight::from_ref_time(4_900_339).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) } - // Storage: Democracy PublicProps (r:0 w:1) + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { - // Minimum execution time: 8_516 nanoseconds. - Weight::from_ref_time(8_747_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_019 nanoseconds. + Weight::from_ref_time(5_321_000) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - // Minimum execution time: 39_703 nanoseconds. - Weight::from_ref_time(48_432_143) - // Standard Error: 1_877 - .saturating_add(Weight::from_ref_time(57_602).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `12647` + // Minimum execution time: 27_151 nanoseconds. + Weight::from_parts(34_372_218, 12647) + // Standard Error: 1_579 + .saturating_add(Weight::from_ref_time(28_501).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - // Minimum execution time: 46_246 nanoseconds. - Weight::from_ref_time(47_528_013) - // Standard Error: 813 - .saturating_add(Weight::from_ref_time(105_549).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `580 + r * (22 ±0)` + // Estimated: `12647` + // Minimum execution time: 32_050 nanoseconds. + Weight::from_parts(33_399_524, 12647) + // Standard Error: 662 + .saturating_add(Weight::from_ref_time(64_466).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - // Minimum execution time: 24_686 nanoseconds. - Weight::from_ref_time(27_710_154) - // Standard Error: 1_399 - .saturating_add(Weight::from_ref_time(105_340).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_029 nanoseconds. + Weight::from_parts(23_451_700, 8946) + // Standard Error: 1_028 + .saturating_add(Weight::from_ref_time(80_162).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - // Minimum execution time: 25_056 nanoseconds. - Weight::from_ref_time(27_534_949) - // Standard Error: 1_155 - .saturating_add(Weight::from_ref_time(107_985).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_149 nanoseconds. + Weight::from_parts(23_859_703, 8946) + // Standard Error: 1_119 + .saturating_add(Weight::from_ref_time(79_988).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/centrifuge/src/weights/pallet_elections_phragmen.rs b/runtime/centrifuge/src/weights/pallet_elections_phragmen.rs index 39363d0768..e799c7e9ca 100644 --- a/runtime/centrifuge/src/weights/pallet_elections_phragmen.rs +++ b/runtime/centrifuge/src/weights/pallet_elections_phragmen.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_elections_phragmen` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,153 +31,247 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_elections_phragmen`. pub struct WeightInfo(PhantomData); impl pallet_elections_phragmen::WeightInfo for WeightInfo { - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - // Minimum execution time: 50_384 nanoseconds. - Weight::from_ref_time(52_605_875) - // Standard Error: 4_831 - .saturating_add(Weight::from_ref_time(202_432).saturating_mul(v.into())) + // Proof Size summary in bytes: + // Measured: `527 + v * (80 ±0)` + // Estimated: `9838 + v * (320 ±0)` + // Minimum execution time: 35_186 nanoseconds. + Weight::from_parts(36_352_142, 9838) + // Standard Error: 2_665 + .saturating_add(Weight::from_ref_time(107_010).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - // Minimum execution time: 67_837 nanoseconds. - Weight::from_ref_time(69_184_036) - // Standard Error: 4_733 - .saturating_add(Weight::from_ref_time(227_700).saturating_mul(v.into())) + // Proof Size summary in bytes: + // Measured: `495 + v * (80 ±0)` + // Estimated: `9710 + v * (320 ±0)` + // Minimum execution time: 49_242 nanoseconds. + Weight::from_parts(50_009_408, 9710) + // Standard Error: 11_445 + .saturating_add(Weight::from_ref_time(197_853).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - // Minimum execution time: 67_536 nanoseconds. - Weight::from_ref_time(69_190_737) - // Standard Error: 5_377 - .saturating_add(Weight::from_ref_time(245_614).saturating_mul(v.into())) + // Proof Size summary in bytes: + // Measured: `527 + v * (80 ±0)` + // Estimated: `9838 + v * (320 ±0)` + // Minimum execution time: 48_580 nanoseconds. + Weight::from_parts(51_296_612, 9838) + // Standard Error: 13_325 + .saturating_add(Weight::from_ref_time(53_074).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn remove_voter() -> Weight { - // Minimum execution time: 64_110 nanoseconds. - Weight::from_ref_time(65_773_000) + // Proof Size summary in bytes: + // Measured: `1017` + // Estimated: `7266` + // Minimum execution time: 45_424 nanoseconds. + Weight::from_parts(46_366_000, 7266) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Elections Candidates (r:1 w:1) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 100]`. fn submit_candidacy(c: u32, ) -> Weight { - // Minimum execution time: 54_381 nanoseconds. - Weight::from_ref_time(55_034_527) - // Standard Error: 1_764 - .saturating_add(Weight::from_ref_time(119_750).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `1635 + c * (48 ±0)` + // Estimated: `6390 + c * (144 ±0)` + // Minimum execution time: 40_004 nanoseconds. + Weight::from_parts(40_085_331, 6390) + // Standard Error: 1_696 + .saturating_add(Weight::from_ref_time(110_947).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } - // Storage: Elections Candidates (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 100]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Minimum execution time: 49_392 nanoseconds. - Weight::from_ref_time(51_491_035) - // Standard Error: 4_213 - .saturating_add(Weight::from_ref_time(72_400).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `414 + c * (48 ±0)` + // Estimated: `895 + c * (48 ±0)` + // Minimum execution time: 36_227 nanoseconds. + Weight::from_parts(36_822_873, 895) + // Standard Error: 1_582 + .saturating_add(Weight::from_ref_time(65_167).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) } - // Storage: Elections Members (r:1 w:1) - // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Council Prime (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Members (r:0 w:1) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { - // Minimum execution time: 67_094 nanoseconds. - Weight::from_ref_time(69_269_000) + // Proof Size summary in bytes: + // Measured: `1783` + // Estimated: `10895` + // Minimum execution time: 54_161 nanoseconds. + Weight::from_parts(55_463_000, 10895) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Elections RunnersUp (r:1 w:1) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { - // Minimum execution time: 52_678 nanoseconds. - Weight::from_ref_time(53_419_000) + // Proof Size summary in bytes: + // Measured: `1086` + // Estimated: `1581` + // Minimum execution time: 38_781 nanoseconds. + Weight::from_parts(39_984_000, 1581) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Benchmark Override (r:0 w:0) + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` // Minimum execution time: 500_000_000 nanoseconds. Weight::from_ref_time(500_000_000_000) } - // Storage: Elections Members (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Council Prime (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Members (r:0 w:1) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { - // Minimum execution time: 91_992 nanoseconds. - Weight::from_ref_time(93_354_000) + // Proof Size summary in bytes: + // Measured: `1918` + // Estimated: `16776` + // Minimum execution time: 81_662 nanoseconds. + Weight::from_parts(82_394_000, 16776) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: Elections Voting (r:501 w:500) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Candidates (r:1 w:0) - // Storage: Balances Locks (r:500 w:500) - // Storage: System Account (r:500 w:500) + /// Storage: Elections Voting (r:1001 w:1000) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1000 w:1000) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. /// The range of component `d` is `[0, 500]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Minimum execution time: 42_365_807 nanoseconds. - Weight::from_ref_time(42_429_186_000) - // Standard Error: 348_050 - .saturating_add(Weight::from_ref_time(51_010_420).saturating_mul(v.into())) + // Proof Size summary in bytes: + // Measured: `3863 + v * (873 ±0)` + // Estimated: `19504 + v * (12348 ±0)` + // Minimum execution time: 42_583_168 nanoseconds. + Weight::from_parts(42_678_065_000, 19504) + // Standard Error: 375_836 + .saturating_add(Weight::from_ref_time(52_817_230).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12348).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:1) - // Storage: Elections Members (r:1 w:1) - // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Elections Voting (r:1001 w:0) - // Storage: Council Proposals (r:1 w:0) - // Storage: Elections ElectionRounds (r:1 w:1) - // Storage: Council Members (r:0 w:1) - // Storage: Council Prime (r:0 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1001 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:83 w:83) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 100]`. /// The range of component `v` is `[1, 1000]`. /// The range of component `e` is `[1000, 16000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Minimum execution time: 3_861_903 nanoseconds. - Weight::from_ref_time(3_878_574_000) - // Standard Error: 478_197 - .saturating_add(Weight::from_ref_time(23_783_592).saturating_mul(v.into())) - // Standard Error: 30_688 - .saturating_add(Weight::from_ref_time(853_755).saturating_mul(e.into())) + // Proof Size summary in bytes: + // Measured: `0 + v * (636 ±0) + e * (28 ±0)` + // Estimated: `530640 + v * (5450 ±6) + e * (106 ±0) + c * (2372 ±3)` + // Minimum execution time: 3_929_077 nanoseconds. + Weight::from_parts(3_943_132_000, 530640) + // Standard Error: 487_751 + .saturating_add(Weight::from_ref_time(24_453_668).saturating_mul(v.into())) + // Standard Error: 31_301 + .saturating_add(Weight::from_ref_time(862_064).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(25)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5450).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(106).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2372).saturating_mul(c.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_fees.rs b/runtime/centrifuge/src/weights/pallet_fees.rs index 6dee8c770e..18fe99143a 100644 --- a/runtime/centrifuge/src/weights/pallet_fees.rs +++ b/runtime/centrifuge/src/weights/pallet_fees.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_fees` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,10 +31,14 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_fees`. pub struct WeightInfo(PhantomData); impl pallet_fees::WeightInfo for WeightInfo { - // Storage: Fees FeeBalances (r:0 w:1) + /// Storage: Fees FeeBalances (r:0 w:1) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn set_fee() -> Weight { - // Minimum execution time: 20_458 nanoseconds. - Weight::from_ref_time(21_210_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_212 nanoseconds. + Weight::from_ref_time(12_674_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/centrifuge/src/weights/pallet_identity.rs b/runtime/centrifuge/src/weights/pallet_identity.rs index f4ced56d26..a0bed33c34 100644 --- a/runtime/centrifuge/src/weights/pallet_identity.rs +++ b/runtime/centrifuge/src/weights/pallet_identity.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_identity` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,209 +31,289 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_identity`. pub struct WeightInfo(PhantomData); impl pallet_identity::WeightInfo for WeightInfo { - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - // Minimum execution time: 26_489 nanoseconds. - Weight::from_ref_time(28_007_649) - // Standard Error: 3_356 - .saturating_add(Weight::from_ref_time(159_094).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `63 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 17_473 nanoseconds. + Weight::from_parts(18_369_416, 1636) + // Standard Error: 2_030 + .saturating_add(Weight::from_ref_time(104_517).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 56_586 nanoseconds. - Weight::from_ref_time(55_725_237) - // Standard Error: 3_855 - .saturating_add(Weight::from_ref_time(137_465).saturating_mul(r.into())) - // Standard Error: 752 - .saturating_add(Weight::from_ref_time(651_498).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `473 + r * (5 ±0)` + // Estimated: `10013` + // Minimum execution time: 40_556 nanoseconds. + Weight::from_parts(39_921_550, 10013) + // Standard Error: 2_599 + .saturating_add(Weight::from_ref_time(84_294).saturating_mul(r.into())) + // Standard Error: 507 + .saturating_add(Weight::from_ref_time(590_284).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:2 w:2) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - // Minimum execution time: 17_682 nanoseconds. - Weight::from_ref_time(37_769_378) - // Standard Error: 73_444 - .saturating_add(Weight::from_ref_time(4_685_735).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `15746 + s * (2589 ±0)` + // Minimum execution time: 12_733 nanoseconds. + Weight::from_parts(29_224_855, 15746) + // Standard Error: 4_247 + .saturating_add(Weight::from_ref_time(4_289_100).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:2) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - // Minimum execution time: 17_703 nanoseconds. - Weight::from_ref_time(63_825_853) - // Standard Error: 34_698 - .saturating_add(Weight::from_ref_time(1_582_520).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `225 + p * (32 ±0)` + // Estimated: `15746` + // Minimum execution time: 12_884 nanoseconds. + Weight::from_parts(28_093_250, 15746) + // Standard Error: 3_656 + .saturating_add(Weight::from_ref_time(1_747_551).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Minimum execution time: 85_620 nanoseconds. - Weight::from_ref_time(52_232_759) - // Standard Error: 10_645 - .saturating_add(Weight::from_ref_time(250_029).saturating_mul(r.into())) - // Standard Error: 2_078 - .saturating_add(Weight::from_ref_time(1_745_113).saturating_mul(s.into())) - // Standard Error: 2_078 - .saturating_add(Weight::from_ref_time(338_969).saturating_mul(x.into())) + fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `532 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `15746` + // Minimum execution time: 69_469 nanoseconds. + Weight::from_parts(39_531_473, 15746) + // Standard Error: 1_256 + .saturating_add(Weight::from_ref_time(1_735_690).saturating_mul(s.into())) + // Standard Error: 1_256 + .saturating_add(Weight::from_ref_time(326_164).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 57_297 nanoseconds. - Weight::from_ref_time(56_367_290) - // Standard Error: 7_177 - .saturating_add(Weight::from_ref_time(147_758).saturating_mul(r.into())) - // Standard Error: 1_400 - .saturating_add(Weight::from_ref_time(669_749).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `430 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 40_936 nanoseconds. + Weight::from_parts(39_012_552, 11649) + // Standard Error: 5_967 + .saturating_add(Weight::from_ref_time(146_018).saturating_mul(r.into())) + // Standard Error: 1_164 + .saturating_add(Weight::from_ref_time(635_596).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 52_238 nanoseconds. - Weight::from_ref_time(52_157_861) - // Standard Error: 7_010 - .saturating_add(Weight::from_ref_time(113_129).saturating_mul(r.into())) - // Standard Error: 1_367 - .saturating_add(Weight::from_ref_time(663_741).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `429 + x * (66 ±0)` + // Estimated: `10013` + // Minimum execution time: 37_049 nanoseconds. + Weight::from_parts(36_361_530, 10013) + // Standard Error: 5_794 + .saturating_add(Weight::from_ref_time(76_744).saturating_mul(r.into())) + // Standard Error: 1_130 + .saturating_add(Weight::from_ref_time(632_161).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - // Minimum execution time: 14_608 nanoseconds. - Weight::from_ref_time(15_453_249) - // Standard Error: 2_263 - .saturating_add(Weight::from_ref_time(130_526).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 10_550 nanoseconds. + Weight::from_parts(11_027_512, 1636) + // Standard Error: 1_346 + .saturating_add(Weight::from_ref_time(80_626).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - // Minimum execution time: 15_028 nanoseconds. - Weight::from_ref_time(15_631_263) - // Standard Error: 2_069 - .saturating_add(Weight::from_ref_time(130_929).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_738 nanoseconds. + Weight::from_parts(10_347_983, 1636) + // Standard Error: 1_009 + .saturating_add(Weight::from_ref_time(69_102).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - // Minimum execution time: 14_707 nanoseconds. - Weight::from_ref_time(15_537_755) - // Standard Error: 1_959 - .saturating_add(Weight::from_ref_time(128_836).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_658 nanoseconds. + Weight::from_parts(9_971_967, 1636) + // Standard Error: 1_052 + .saturating_add(Weight::from_ref_time(73_458).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - // Minimum execution time: 41_818 nanoseconds. - Weight::from_ref_time(40_739_730) - // Standard Error: 7_824 - .saturating_add(Weight::from_ref_time(189_060).saturating_mul(r.into())) - // Standard Error: 1_447 - .saturating_add(Weight::from_ref_time(1_086_494).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `508 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 31_008 nanoseconds. + Weight::from_parts(29_685_247, 11649) + // Standard Error: 6_315 + .saturating_add(Weight::from_ref_time(121_805).saturating_mul(r.into())) + // Standard Error: 1_168 + .saturating_add(Weight::from_ref_time(1_011_953).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Identity SuperOf (r:0 w:100) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Minimum execution time: 105_516 nanoseconds. - Weight::from_ref_time(71_921_769) - // Standard Error: 10_646 - .saturating_add(Weight::from_ref_time(147_691).saturating_mul(r.into())) - // Standard Error: 2_079 - .saturating_add(Weight::from_ref_time(1_759_855).saturating_mul(s.into())) - // Standard Error: 2_079 - .saturating_add(Weight::from_ref_time(345_058).saturating_mul(x.into())) + // Proof Size summary in bytes: + // Measured: `892 + r * (15 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `20952` + // Minimum execution time: 92_482 nanoseconds. + Weight::from_parts(61_391_463, 20952) + // Standard Error: 7_976 + .saturating_add(Weight::from_ref_time(97_443).saturating_mul(r.into())) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(1_773_014).saturating_mul(s.into())) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(323_185).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - // Minimum execution time: 51_777 nanoseconds. - Weight::from_ref_time(58_241_836) - // Standard Error: 1_706 - .saturating_add(Weight::from_ref_time(107_333).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `506 + s * (36 ±0)` + // Estimated: `18335` + // Minimum execution time: 37_289 nanoseconds. + Weight::from_parts(41_999_609, 18335) + // Standard Error: 1_216 + .saturating_add(Weight::from_ref_time(75_273).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - // Minimum execution time: 22_542 nanoseconds. - Weight::from_ref_time(25_241_673) - // Standard Error: 784 - .saturating_add(Weight::from_ref_time(34_037).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `622 + s * (3 ±0)` + // Estimated: `12602` + // Minimum execution time: 16_290 nanoseconds. + Weight::from_parts(20_452_207, 12602) + // Standard Error: 3_339 + .saturating_add(Weight::from_ref_time(17_119).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - // Minimum execution time: 55_934 nanoseconds. - Weight::from_ref_time(60_334_240) - // Standard Error: 1_354 - .saturating_add(Weight::from_ref_time(90_611).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `701 + s * (35 ±0)` + // Estimated: `18335` + // Minimum execution time: 40_656 nanoseconds. + Weight::from_parts(43_935_052, 18335) + // Standard Error: 1_065 + .saturating_add(Weight::from_ref_time(62_066).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - // Minimum execution time: 39_233 nanoseconds. - Weight::from_ref_time(43_479_539) - // Standard Error: 1_258 - .saturating_add(Weight::from_ref_time(92_062).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `627 + s * (37 ±0)` + // Estimated: `8322` + // Minimum execution time: 27_552 nanoseconds. + Weight::from_parts(29_791_045, 8322) + // Standard Error: 986 + .saturating_add(Weight::from_ref_time(63_817).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/centrifuge/src/weights/pallet_interest_accrual.rs b/runtime/centrifuge/src/weights/pallet_interest_accrual.rs index 36b404e3e4..ffd4bf0940 100644 --- a/runtime/centrifuge/src/weights/pallet_interest_accrual.rs +++ b/runtime/centrifuge/src/weights/pallet_interest_accrual.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_interest_accrual` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -32,9 +33,12 @@ pub struct WeightInfo(PhantomData); impl pallet_interest_accrual::WeightInfo for WeightInfo { /// The range of component `n` is `[1, 25]`. fn calculate_accumulated_rate(n: u32, ) -> Weight { - // Minimum execution time: 651 nanoseconds. - Weight::from_ref_time(212_129) - // Standard Error: 424 - .saturating_add(Weight::from_ref_time(614_892).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 671 nanoseconds. + Weight::from_ref_time(181_268) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(645_249).saturating_mul(n.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_keystore.rs b/runtime/centrifuge/src/weights/pallet_keystore.rs index 8eb85e1b1a..88bffeb7ce 100644 --- a/runtime/centrifuge/src/weights/pallet_keystore.rs +++ b/runtime/centrifuge/src/weights/pallet_keystore.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_keystore` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,35 +31,52 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_keystore`. pub struct WeightInfo(PhantomData); impl pallet_keystore::WeightInfo for WeightInfo { - // Storage: Keystore KeyDeposit (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Keystore Keys (r:1 w:1) - // Storage: Keystore LastKeyByPurpose (r:0 w:1) + /// Storage: Keystore KeyDeposit (r:1 w:0) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) + /// Storage: Keystore LastKeyByPurpose (r:0 w:1) + /// Proof: Keystore LastKeyByPurpose (max_values: None, max_size: Some(97), added: 2572, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn add_keys(n: u32, ) -> Weight { - // Minimum execution time: 46_877 nanoseconds. - Weight::from_ref_time(27_236_613) - // Standard Error: 12_118 - .saturating_add(Weight::from_ref_time(21_832_427).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `3114 + n * (2595 ±0)` + // Minimum execution time: 37_820 nanoseconds. + Weight::from_parts(17_122_053, 3114) + // Standard Error: 11_215 + .saturating_add(Weight::from_ref_time(22_611_583).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - // Storage: Keystore Keys (r:1 w:1) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn revoke_keys(n: u32, ) -> Weight { - // Minimum execution time: 30_968 nanoseconds. - Weight::from_ref_time(20_261_880) - // Standard Error: 13_719 - .saturating_add(Weight::from_ref_time(12_291_737).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `148 + n * (75 ±0)` + // Estimated: `0 + n * (2595 ±0)` + // Minimum execution time: 21_890 nanoseconds. + Weight::from_ref_time(10_946_013) + // Standard Error: 12_666 + .saturating_add(Weight::from_ref_time(12_587_510).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - // Storage: Keystore KeyDeposit (r:0 w:1) + /// Storage: Keystore KeyDeposit (r:0 w:1) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_deposit() -> Weight { - // Minimum execution time: 20_428 nanoseconds. - Weight::from_ref_time(21_119_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_722 nanoseconds. + Weight::from_ref_time(11_993_000) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/centrifuge/src/weights/pallet_liquidity_rewards.rs b/runtime/centrifuge/src/weights/pallet_liquidity_rewards.rs new file mode 100644 index 0000000000..58b8b1f92a --- /dev/null +++ b/runtime/centrifuge/src/weights/pallet_liquidity_rewards.rs @@ -0,0 +1,37 @@ +//! File pending to be auto-generated + +use frame_support::weights::Weight; +pub struct WeightInfo(sp_std::marker::PhantomData); +impl pallet_liquidity_rewards::WeightInfo for WeightInfo { + fn on_initialize(_: u32, _: u32, _: u32) -> Weight { + Weight::zero() + } + + fn stake() -> Weight { + Weight::zero() + } + + fn unstake() -> Weight { + Weight::zero() + } + + fn claim_reward() -> Weight { + Weight::zero() + } + + fn set_distributed_reward() -> Weight { + Weight::zero() + } + + fn set_epoch_duration() -> Weight { + Weight::zero() + } + + fn set_group_weight() -> Weight { + Weight::zero() + } + + fn set_currency_group() -> Weight { + Weight::zero() + } +} diff --git a/runtime/centrifuge/src/weights/pallet_loans.rs b/runtime/centrifuge/src/weights/pallet_loans.rs index ae242aaff5..8d398a8a30 100644 --- a/runtime/centrifuge/src/weights/pallet_loans.rs +++ b/runtime/centrifuge/src/weights/pallet_loans.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_loans` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,146 +31,264 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_loans`. pub struct WeightInfo(PhantomData); impl pallet_loans::WeightInfo for WeightInfo { - // Storage: Permissions Permission (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Uniques Class (r:1 w:0) - // Storage: Loans LastLoanId (r:1 w:1) - // Storage: Loans CreatedLoan (r:0 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Loans LastLoanId (r:1 w:1) + /// Proof: Loans LastLoanId (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Loans CreatedLoan (r:0 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 89_537 nanoseconds. - Weight::from_ref_time(91_060_000) + // Proof Size summary in bytes: + // Measured: `1200` + // Estimated: `14271` + // Minimum execution time: 78_445 nanoseconds. + Weight::from_parts(80_269_000, 14271) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(6)) } - // Storage: Loans CreatedLoan (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:0) - /// The range of component `n` is `[1, 999]`. + /// Storage: Loans CreatedLoan (r:1 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn borrow(n: u32, ) -> Weight { - // Minimum execution time: 251_890 nanoseconds. - Weight::from_ref_time(273_565_605) - // Standard Error: 2_350 - .saturating_add(Weight::from_ref_time(644_110).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `38172 + n * (340 ±0)` + // Estimated: `406331` + // Minimum execution time: 227_263 nanoseconds. + Weight::from_parts(253_204_926, 406331) + // Standard Error: 60_800 + .saturating_add(Weight::from_ref_time(821_079).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:0) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:0) - /// The range of component `n` is `[1, 999]`. + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn repay(n: u32, ) -> Weight { - // Minimum execution time: 185_066 nanoseconds. - Weight::from_ref_time(207_612_048) - // Standard Error: 3_009 - .saturating_add(Weight::from_ref_time(629_121).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `38228 + n * (340 ±0)` + // Estimated: `403628` + // Minimum execution time: 169_776 nanoseconds. + Weight::from_parts(191_203_662, 403628) + // Standard Error: 53_978 + .saturating_add(Weight::from_ref_time(113_323).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Loans WriteOffPolicy (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - /// The range of component `n` is `[1, 999]`. + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn write_off(n: u32, ) -> Weight { - // Minimum execution time: 350_203 nanoseconds. - Weight::from_ref_time(365_819_358) - // Standard Error: 2_270 - .saturating_add(Weight::from_ref_time(635_015).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `41236 + n * (340 ±0)` + // Estimated: `400130` + // Minimum execution time: 325_475 nanoseconds. + Weight::from_parts(350_248_170, 400130) + // Standard Error: 109_838 + .saturating_add(Weight::from_ref_time(964_862).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: Loans WriteOffPolicy (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: InterestAccrual LastUpdated (r:1 w:0) - /// The range of component `n` is `[1, 999]`. - fn admin_write_off(n: u32, ) -> Weight { - // Minimum execution time: 359_230 nanoseconds. - Weight::from_ref_time(386_280_476) - // Standard Error: 2_103 - .saturating_add(Weight::from_ref_time(631_826).saturating_mul(n.into())) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn admin_write_off(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `41487 + n * (340 ±0)` + // Estimated: `402833` + // Minimum execution time: 327_749 nanoseconds. + Weight::from_parts(370_644_004, 402833) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Loans CreatedLoan (r:1 w:0) - // Storage: Loans ActiveLoans (r:1 w:1) - // Storage: InterestAccrual Rates (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Loans ClosedLoan (r:0 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) - /// The range of component `n` is `[1, 999]`. + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn propose_loan_mutation(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `937 + n * (316 ±0)` + // Estimated: `331707` + // Minimum execution time: 47_298 nanoseconds. + Weight::from_parts(59_693_193, 331707) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn apply_loan_mutation(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `37573 + n * (340 ±0)` + // Estimated: `403476` + // Minimum execution time: 105_336 nanoseconds. + Weight::from_parts(114_925_228, 403476) + // Standard Error: 60_749 + .saturating_add(Weight::from_ref_time(665_077).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Loans CreatedLoan (r:1 w:0) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Loans ClosedLoan (r:0 w:1) + /// Proof: Loans ClosedLoan (max_values: None, max_size: Some(264), added: 2739, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. fn close(n: u32, ) -> Weight { - // Minimum execution time: 147_966 nanoseconds. - Weight::from_ref_time(162_508_504) - // Standard Error: 1_924 - .saturating_add(Weight::from_ref_time(602_264).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `37335 + n * (349 ±0)` + // Estimated: `372971` + // Minimum execution time: 127_888 nanoseconds. + Weight::from_parts(143_685_633, 372971) + // Standard Error: 67_849 + .saturating_add(Weight::from_ref_time(1_624_004).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(7)) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Loans WriteOffPolicy (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) fn propose_write_off_policy() -> Weight { - // Minimum execution time: 96_169 nanoseconds. - Weight::from_ref_time(97_501_000) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `512` + // Estimated: `6494` + // Minimum execution time: 88_714 nanoseconds. + Weight::from_parts(90_268_000, 6494) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - fn propose_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - - fn apply_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Loans WriteOffPolicy (r:0 w:1) + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) fn apply_write_off_policy() -> Weight { - // Minimum execution time: 96_169 nanoseconds. - Weight::from_ref_time(97_501_000) + // Proof Size summary in bytes: + // Measured: `4950` + // Estimated: `10947` + // Minimum execution time: 92_231 nanoseconds. + Weight::from_parts(93_674_000, 10947) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: InterestAccrual Rates (r:1 w:0) - // Storage: Loans ActiveLoans (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:1) - /// The range of component `n` is `[1, 1000]`. + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: PriceCollector Collection (r:1 w:0) + /// Proof: PriceCollector Collection (max_values: None, max_size: Some(37026), added: 39501, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:0 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. fn update_portfolio_valuation(n: u32, ) -> Weight { - // Minimum execution time: 88_244 nanoseconds. - Weight::from_ref_time(92_924_938) - // Standard Error: 1_332 - .saturating_add(Weight::from_ref_time(10_008_833).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `36994 + n * (316 ±0)` + // Estimated: `408290` + // Minimum execution time: 93_484 nanoseconds. + Weight::from_parts(90_559_384, 408290) + // Standard Error: 44_883 + .saturating_add(Weight::from_ref_time(10_213_860).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_migration_manager.rs b/runtime/centrifuge/src/weights/pallet_migration_manager.rs index 16c566b87b..2774f4727d 100644 --- a/runtime/centrifuge/src/weights/pallet_migration_manager.rs +++ b/runtime/centrifuge/src/weights/pallet_migration_manager.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_migration_manager` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,55 +31,81 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_migration_manager`. pub struct WeightInfo(PhantomData); impl pallet_migration_manager::WeightInfo for WeightInfo { - // Storage: Migration Status (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn finalize() -> Weight { - // Minimum execution time: 26_530 nanoseconds. - Weight::from_ref_time(27_171_000) + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `496` + // Minimum execution time: 17_212 nanoseconds. + Weight::from_parts(17_723_000, 496) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Migration Status (r:1 w:1) - // Storage: System Account (r:0 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: System Account (r:0 w:100) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 100]`. fn migrate_system_account(n: u32, ) -> Weight { - // Minimum execution time: 28_784 nanoseconds. - Weight::from_ref_time(29_183_333) - // Standard Error: 1_796 - .saturating_add(Weight::from_ref_time(1_099_906).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 18_645 nanoseconds. + Weight::from_parts(18_361_813, 496) + // Standard Error: 1_647 + .saturating_add(Weight::from_ref_time(1_082_059).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } - // Storage: Migration Status (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn migrate_balances_issuance() -> Weight { - // Minimum execution time: 32_249 nanoseconds. - Weight::from_ref_time(33_352_000) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 19_366 nanoseconds. + Weight::from_parts(19_897_000, 496) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Migration Status (r:1 w:1) - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:10 w:10) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:10 w:10) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:10 w:10) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn migrate_vesting_vesting(n: u32, ) -> Weight { - // Minimum execution time: 91_100 nanoseconds. - Weight::from_ref_time(61_079_468) - // Standard Error: 49_454 - .saturating_add(Weight::from_ref_time(35_421_064).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `363 + n * (461 ±0)` + // Estimated: `496 + n * (9009 ±0)` + // Minimum execution time: 66_404 nanoseconds. + Weight::from_parts(33_512_133, 496) + // Standard Error: 83_617 + .saturating_add(Weight::from_ref_time(36_066_009).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(9009).saturating_mul(n.into())) } - // Storage: Migration Status (r:1 w:1) - // Storage: Proxy Proxies (r:0 w:1) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Proxy Proxies (r:0 w:10) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10]`. fn migrate_proxy_proxies(n: u32, ) -> Weight { - // Minimum execution time: 50_223 nanoseconds. - Weight::from_ref_time(45_127_512) - // Standard Error: 19_141 - .saturating_add(Weight::from_ref_time(7_963_307).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 35_276 nanoseconds. + Weight::from_parts(36_808_128, 496) + // Standard Error: 76_342 + .saturating_add(Weight::from_ref_time(7_400_912).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) diff --git a/runtime/centrifuge/src/weights/pallet_multisig.rs b/runtime/centrifuge/src/weights/pallet_multisig.rs index bfbdd9f763..25a548cb6e 100644 --- a/runtime/centrifuge/src/weights/pallet_multisig.rs +++ b/runtime/centrifuge/src/weights/pallet_multisig.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -32,80 +33,106 @@ pub struct WeightInfo(PhantomData); impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { - // Minimum execution time: 21_700 nanoseconds. - Weight::from_ref_time(22_950_659) - // Standard Error: 8 - .saturating_add(Weight::from_ref_time(570).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 17_002 nanoseconds. + Weight::from_ref_time(17_991_010) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(462).saturating_mul(z.into())) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 66_755 nanoseconds. - Weight::from_ref_time(56_807_393) - // Standard Error: 1_141 - .saturating_add(Weight::from_ref_time(118_573).saturating_mul(s.into())) - // Standard Error: 11 - .saturating_add(Weight::from_ref_time(1_791).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 49_753 nanoseconds. + Weight::from_parts(42_172_090, 5821) + // Standard Error: 856 + .saturating_add(Weight::from_ref_time(93_901).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_764).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 47_669 nanoseconds. - Weight::from_ref_time(38_813_956) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(107_334).saturating_mul(s.into())) - // Standard Error: 9 - .saturating_add(Weight::from_ref_time(1_803).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 35_125 nanoseconds. + Weight::from_parts(28_524_177, 5821) + // Standard Error: 674 + .saturating_add(Weight::from_ref_time(84_976).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_707).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // Minimum execution time: 71_413 nanoseconds. - Weight::from_ref_time(69_419_235) - // Standard Error: 8_465 - .saturating_add(Weight::from_ref_time(44_428).saturating_mul(s.into())) - // Standard Error: 82 - .saturating_add(Weight::from_ref_time(1_683).saturating_mul(z.into())) + // Proof Size summary in bytes: + // Measured: `550 + s * (33 ±0)` + // Estimated: `8424` + // Minimum execution time: 57_507 nanoseconds. + Weight::from_parts(47_349_367, 8424) + // Standard Error: 1_179 + .saturating_add(Weight::from_ref_time(122_246).saturating_mul(s.into())) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(1_733).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // Minimum execution time: 51_807 nanoseconds. - Weight::from_ref_time(54_046_877) - // Standard Error: 1_195 - .saturating_add(Weight::from_ref_time(126_803).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 38_322 nanoseconds. + Weight::from_parts(40_334_565, 5821) + // Standard Error: 1_057 + .saturating_add(Weight::from_ref_time(94_166).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // Minimum execution time: 35_546 nanoseconds. - Weight::from_ref_time(36_707_799) - // Standard Error: 1_060 - .saturating_add(Weight::from_ref_time(111_392).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 25_136 nanoseconds. + Weight::from_parts(25_678_732, 5821) + // Standard Error: 1_258 + .saturating_add(Weight::from_ref_time(94_962).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // Minimum execution time: 49_242 nanoseconds. - Weight::from_ref_time(51_709_727) - // Standard Error: 1_143 - .saturating_add(Weight::from_ref_time(116_233).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `616 + s * (1 ±0)` + // Estimated: `5821` + // Minimum execution time: 39_794 nanoseconds. + Weight::from_parts(41_043_473, 5821) + // Standard Error: 1_213 + .saturating_add(Weight::from_ref_time(101_266).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_permissions.rs b/runtime/centrifuge/src/weights/pallet_permissions.rs index b306502bb1..112e86ac83 100644 --- a/runtime/centrifuge/src/weights/pallet_permissions.rs +++ b/runtime/centrifuge/src/weights/pallet_permissions.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_permissions` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,49 +31,77 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_permissions`. pub struct WeightInfo(PhantomData); impl pallet_permissions::WeightInfo for WeightInfo { - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn add_as_admin() -> Weight { - // Minimum execution time: 31_789 nanoseconds. - Weight::from_ref_time(32_581_000) + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `5224` + // Minimum execution time: 20_849 nanoseconds. + Weight::from_parts(21_610_000, 5224) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn add_as_editor() -> Weight { - // Minimum execution time: 39_213 nanoseconds. - Weight::from_ref_time(40_075_000) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `7927` + // Minimum execution time: 28_834 nanoseconds. + Weight::from_parts(29_285_000, 7927) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn remove_as_admin() -> Weight { - // Minimum execution time: 34_605 nanoseconds. - Weight::from_ref_time(35_106_000) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `5224` + // Minimum execution time: 24_476 nanoseconds. + Weight::from_parts(25_077_000, 5224) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn remove_as_editor() -> Weight { - // Minimum execution time: 41_808 nanoseconds. - Weight::from_ref_time(42_489_000) + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `7927` + // Minimum execution time: 31_278 nanoseconds. + Weight::from_parts(31_940_000, 7927) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn purge() -> Weight { - // Minimum execution time: 31_870 nanoseconds. - Weight::from_ref_time(32_461_000) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 20_979 nanoseconds. + Weight::from_parts(22_192_000, 2703) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Permissions Permission (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn admin_purge() -> Weight { - // Minimum execution time: 31_799 nanoseconds. - Weight::from_ref_time(32_641_000) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 21_640 nanoseconds. + Weight::from_parts(22_482_000, 2703) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_pool_registry.rs b/runtime/centrifuge/src/weights/pallet_pool_registry.rs index c28aefd5b4..9d5d90a1af 100644 --- a/runtime/centrifuge/src/weights/pallet_pool_registry.rs +++ b/runtime/centrifuge/src/weights/pallet_pool_registry.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_pool_registry` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,83 +31,134 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_pool_registry`. pub struct WeightInfo(PhantomData); impl pallet_pool_registry::WeightInfo for WeightInfo { - // Storage: PoolRegistry Pools (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: PoolSystem AccountDeposit (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) - // Storage: Permissions PermissionCount (r:1 w:1) - // Storage: Permissions Permission (r:1 w:1) - // Storage: PoolSystem PoolDeposit (r:0 w:1) + /// Storage: PoolRegistry Pools (r:1 w:1) + /// Proof: PoolRegistry Pools (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:6 w:5) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: PoolSystem AccountDeposit (r:1 w:1) + /// Proof: PoolSystem AccountDeposit (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: PoolSystem PoolDeposit (r:0 w:1) + /// Proof: PoolSystem PoolDeposit (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn register(n: u32, ) -> Weight { - // Minimum execution time: 108_001 nanoseconds. - Weight::from_ref_time(95_520_181) - // Standard Error: 38_092 - .saturating_add(Weight::from_ref_time(15_912_320).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `675` + // Estimated: `19807 + n * (2475 ±0)` + // Minimum execution time: 153_326 nanoseconds. + Weight::from_parts(139_206_198, 19807) + // Standard Error: 188_717 + .saturating_add(Weight::from_ref_time(16_937_683).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(8)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2475).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn update_no_execution(n: u32, ) -> Weight { - // Minimum execution time: 61_345 nanoseconds. - Weight::from_ref_time(61_293_148) - // Standard Error: 15_285 - .saturating_add(Weight::from_ref_time(2_286_521).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `819 + n * (133 ±0)` + // Estimated: `9739 + n * (2531 ±0)` + // Minimum execution time: 48_650 nanoseconds. + Weight::from_parts(48_089_534, 9739) + // Standard Error: 15_208 + .saturating_add(Weight::from_ref_time(2_369_740).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2531).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) - // Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn update_and_execute(n: u32, ) -> Weight { - // Minimum execution time: 92_363 nanoseconds. - Weight::from_ref_time(87_110_520) - // Standard Error: 30_201 - .saturating_add(Weight::from_ref_time(7_930_760).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `910 + n * (167 ±0)` + // Estimated: `15599 + n * (2699 ±0)` + // Minimum execution time: 83_606 nanoseconds. + Weight::from_parts(77_925_350, 15599) + // Standard Error: 37_965 + .saturating_add(Weight::from_ref_time(8_314_113).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2699).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: PoolSystem ScheduledUpdate (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:0) - // Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:1 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[1, 5]`. fn execute_update(n: u32, ) -> Weight { - // Minimum execution time: 80_120 nanoseconds. - Weight::from_ref_time(74_863_525) - // Standard Error: 23_948 - .saturating_add(Weight::from_ref_time(7_884_790).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `932 + n * (194 ±0)` + // Estimated: `16412 + n * (2725 ±0)` + // Minimum execution time: 72_314 nanoseconds. + Weight::from_parts(66_320_482, 16412) + // Standard Error: 41_355 + .saturating_add(Weight::from_ref_time(8_428_684).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2725).saturating_mul(n.into())) } - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolRegistry PoolMetadata (r:0 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolRegistry PoolMetadata (r:0 w:1) + /// Proof: PoolRegistry PoolMetadata (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) /// The range of component `n` is `[0, 46]`. fn set_metadata(n: u32, ) -> Weight { - // Minimum execution time: 33_432 nanoseconds. - Weight::from_ref_time(35_144_895) - // Standard Error: 1_253 - .saturating_add(Weight::from_ref_time(18_014).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 22_411 nanoseconds. + Weight::from_parts(23_553_917, 2703) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(5_442).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_pool_system.rs b/runtime/centrifuge/src/weights/pallet_pool_system.rs index 18f1fac0e1..9a17b23b30 100644 --- a/runtime/centrifuge/src/weights/pallet_pool_system.rs +++ b/runtime/centrifuge/src/weights/pallet_pool_system.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_pool_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,121 +31,201 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_pool_system`. pub struct WeightInfo(PhantomData); impl pallet_pool_system::WeightInfo for WeightInfo { - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) fn set_max_reserve() -> Weight { - // Minimum execution time: 41_668 nanoseconds. - Weight::from_ref_time(43_321_000) + // Proof Size summary in bytes: + // Measured: `657` + // Estimated: `5991` + // Minimum execution time: 29_746 nanoseconds. + Weight::from_parts(30_197_000, 5991) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:5 w:0) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_orders(n: u32, ) -> Weight { - // Minimum execution time: 138_598 nanoseconds. - Weight::from_ref_time(61_521_077) - // Standard Error: 39_873 - .saturating_add(Weight::from_ref_time(79_873_444).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `841 + n * (133 ±0)` + // Estimated: `33561 + n * (20298 ±0)` + // Minimum execution time: 121_947 nanoseconds. + Weight::from_parts(50_340_346, 33561) + // Standard Error: 43_332 + .saturating_add(Weight::from_ref_time(74_108_151).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_execution(n: u32, ) -> Weight { - // Minimum execution time: 97_983 nanoseconds. - Weight::from_ref_time(69_053_915) - // Standard Error: 31_896 - .saturating_add(Weight::from_ref_time(32_513_282).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `1007 + n * (133 ±0)` + // Estimated: `33561 + n * (17694 ±0)` + // Minimum execution time: 83_635 nanoseconds. + Weight::from_parts(54_862_697, 33561) + // Standard Error: 34_507 + .saturating_add(Weight::from_ref_time(31_508_266).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17694).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PortfolioValuation (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_execute(n: u32, ) -> Weight { - // Minimum execution time: 230_439 nanoseconds. - Weight::from_ref_time(152_790_769) - // Standard Error: 63_987 - .saturating_add(Weight::from_ref_time(81_525_082).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `1525 + n * (133 ±0)` + // Estimated: `43975 + n * (20298 ±0)` + // Minimum execution time: 209_289 nanoseconds. + Weight::from_parts(138_046_977, 43975) + // Standard Error: 59_696 + .saturating_add(Weight::from_ref_time(75_664_781).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(7)) .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:0) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn submit_solution(n: u32, ) -> Weight { - // Minimum execution time: 43_050 nanoseconds. - Weight::from_ref_time(43_399_199) - // Standard Error: 13_599 - .saturating_add(Weight::from_ref_time(1_132_749).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `493 + n * (249 ±0)` + // Estimated: `6533` + // Minimum execution time: 30_777 nanoseconds. + Weight::from_parts(31_524_649, 6533) + // Standard Error: 13_304 + .saturating_add(Weight::from_ref_time(771_497).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:0) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:0) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn execute_epoch(n: u32, ) -> Weight { - // Minimum execution time: 196_797 nanoseconds. - Weight::from_ref_time(141_281_270) - // Standard Error: 42_287 - .saturating_add(Weight::from_ref_time(58_624_837).saturating_mul(n.into())) + // Proof Size summary in bytes: + // Measured: `1503 + n * (605 ±0)` + // Estimated: `19974 + n * (17774 ±0)` + // Minimum execution time: 175_236 nanoseconds. + Weight::from_parts(124_344_158, 19974) + // Standard Error: 43_193 + .saturating_add(Weight::from_ref_time(54_899_238).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(8)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(n.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_preimage.rs b/runtime/centrifuge/src/weights/pallet_preimage.rs index a90c90a7b0..3d871bfc0b 100644 --- a/runtime/centrifuge/src/weights/pallet_preimage.rs +++ b/runtime/centrifuge/src/weights/pallet_preimage.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_preimage` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,102 +31,156 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_preimage`. pub struct WeightInfo(PhantomData); impl pallet_preimage::WeightInfo for WeightInfo { - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - // Minimum execution time: 46_847 nanoseconds. - Weight::from_ref_time(199_714_337) - // Standard Error: 16 - .saturating_add(Weight::from_ref_time(2_303).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `209` + // Estimated: `2566` + // Minimum execution time: 36_317 nanoseconds. + Weight::from_parts(82_180_035, 2566) + // Standard Error: 18 + .saturating_add(Weight::from_ref_time(2_389).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - // Minimum execution time: 32_641 nanoseconds. - Weight::from_ref_time(26_594_355) - // Standard Error: 15 - .saturating_add(Weight::from_ref_time(2_527).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 23_804 nanoseconds. + Weight::from_parts(1_075_216, 2566) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(2_539).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Minimum execution time: 30_286 nanoseconds. - Weight::from_ref_time(30_738_000) - // Standard Error: 9 - .saturating_add(Weight::from_ref_time(2_504).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 22_502 nanoseconds. + Weight::from_parts(22_822_000, 2566) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(2_481).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { - // Minimum execution time: 57_327 nanoseconds. - Weight::from_ref_time(64_039_000) + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `2566` + // Minimum execution time: 53_900 nanoseconds. + Weight::from_parts(57_466_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_no_deposit_preimage() -> Weight { - // Minimum execution time: 39_965 nanoseconds. - Weight::from_ref_time(43_742_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 35_747 nanoseconds. + Weight::from_parts(41_898_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { - // Minimum execution time: 38_121 nanoseconds. - Weight::from_ref_time(40_386_000) + // Proof Size summary in bytes: + // Measured: `254` + // Estimated: `2566` + // Minimum execution time: 33_192 nanoseconds. + Weight::from_parts(35_406_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_no_deposit_preimage() -> Weight { - // Minimum execution time: 19_837 nanoseconds. - Weight::from_ref_time(21_861_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 22_562 nanoseconds. + Weight::from_parts(25_358_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_unnoted_preimage() -> Weight { - // Minimum execution time: 28_593 nanoseconds. - Weight::from_ref_time(29_435_000) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `2566` + // Minimum execution time: 21_160 nanoseconds. + Weight::from_parts(22_351_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_requested_preimage() -> Weight { - // Minimum execution time: 13_815 nanoseconds. - Weight::from_ref_time(14_477_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_333 nanoseconds. + Weight::from_parts(13_284_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unrequest_preimage() -> Weight { - // Minimum execution time: 38_883 nanoseconds. - Weight::from_ref_time(41_668_000) + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 39_734 nanoseconds. + Weight::from_parts(43_110_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_unnoted_preimage() -> Weight { - // Minimum execution time: 14_116 nanoseconds. - Weight::from_ref_time(14_607_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_663 nanoseconds. + Weight::from_parts(14_076_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_multi_referenced_preimage() -> Weight { - // Minimum execution time: 14_027 nanoseconds. - Weight::from_ref_time(14_567_000) + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_323 nanoseconds. + Weight::from_parts(13_255_000, 2566) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_proxy.rs b/runtime/centrifuge/src/weights/pallet_proxy.rs index 0059e4fdd0..8d6bd87d05 100644 --- a/runtime/centrifuge/src/weights/pallet_proxy.rs +++ b/runtime/centrifuge/src/weights/pallet_proxy.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,121 +31,166 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - // Storage: Proxy Proxies (r:1 w:0) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - // Minimum execution time: 31_960 nanoseconds. - Weight::from_ref_time(33_345_051) - // Standard Error: 2_253 - .saturating_add(Weight::from_ref_time(53_272).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 22_162 nanoseconds. + Weight::from_parts(23_207_581, 3716) + // Standard Error: 1_644 + .saturating_add(Weight::from_ref_time(48_182).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 60_192 nanoseconds. - Weight::from_ref_time(60_791_298) - // Standard Error: 2_796 - .saturating_add(Weight::from_ref_time(240_236).saturating_mul(a.into())) - // Standard Error: 2_888 - .saturating_add(Weight::from_ref_time(40_185).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `650 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 47_579 nanoseconds. + Weight::from_parts(47_977_353, 11027) + // Standard Error: 2_247 + .saturating_add(Weight::from_ref_time(174_754).saturating_mul(a.into())) + // Standard Error: 2_321 + .saturating_add(Weight::from_ref_time(35_796).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 40_826 nanoseconds. - Weight::from_ref_time(42_564_499) - // Standard Error: 2_209 - .saturating_add(Weight::from_ref_time(234_764).saturating_mul(a.into())) - // Standard Error: 2_282 - .saturating_add(Weight::from_ref_time(7_881).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 28_593 nanoseconds. + Weight::from_parts(29_844_862, 7311) + // Standard Error: 1_743 + .saturating_add(Weight::from_ref_time(177_203).saturating_mul(a.into())) + // Standard Error: 1_801 + .saturating_add(Weight::from_ref_time(2_655).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 40_927 nanoseconds. - Weight::from_ref_time(42_495_150) - // Standard Error: 2_354 - .saturating_add(Weight::from_ref_time(239_555).saturating_mul(a.into())) - // Standard Error: 2_432 - .saturating_add(Weight::from_ref_time(7_810).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 28_463 nanoseconds. + Weight::from_parts(29_753_645, 7311) + // Standard Error: 1_779 + .saturating_add(Weight::from_ref_time(181_206).saturating_mul(a.into())) + // Standard Error: 1_839 + .saturating_add(Weight::from_ref_time(6_354).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_369 nanoseconds. - Weight::from_ref_time(57_056_991) - // Standard Error: 27_966 - .saturating_add(Weight::from_ref_time(276_441).saturating_mul(a.into())) - // Standard Error: 28_894 - .saturating_add(Weight::from_ref_time(42_654).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `582 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 40_064 nanoseconds. + Weight::from_parts(41_776_629, 11027) + // Standard Error: 2_262 + .saturating_add(Weight::from_ref_time(174_192).saturating_mul(a.into())) + // Standard Error: 2_337 + .saturating_add(Weight::from_ref_time(36_204).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - // Minimum execution time: 44_893 nanoseconds. - Weight::from_ref_time(46_421_390) - // Standard Error: 2_134 - .saturating_add(Weight::from_ref_time(102_382).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_138 nanoseconds. + Weight::from_parts(32_270_293, 3716) + // Standard Error: 1_752 + .saturating_add(Weight::from_ref_time(59_420).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - // Minimum execution time: 44_924 nanoseconds. - Weight::from_ref_time(46_814_953) - // Standard Error: 2_515 - .saturating_add(Weight::from_ref_time(105_280).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_108 nanoseconds. + Weight::from_parts(32_301_855, 3716) + // Standard Error: 1_597 + .saturating_add(Weight::from_ref_time(64_128).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - // Minimum execution time: 38_612 nanoseconds. - Weight::from_ref_time(40_321_344) - // Standard Error: 1_969 - .saturating_add(Weight::from_ref_time(54_557).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 24_976 nanoseconds. + Weight::from_parts(25_932_811, 3716) + // Standard Error: 1_377 + .saturating_add(Weight::from_ref_time(43_231).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - // Minimum execution time: 50_464 nanoseconds. - Weight::from_ref_time(52_531_891) - // Standard Error: 2_502 - .saturating_add(Weight::from_ref_time(45_403).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `239` + // Estimated: `3716` + // Minimum execution time: 34_284 nanoseconds. + Weight::from_parts(35_197_303, 3716) + // Standard Error: 1_443 + .saturating_add(Weight::from_ref_time(18_362).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - // Minimum execution time: 40_977 nanoseconds. - Weight::from_ref_time(42_356_224) - // Standard Error: 2_037 - .saturating_add(Weight::from_ref_time(50_389).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `296 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 25_999 nanoseconds. + Weight::from_parts(26_856_655, 3716) + // Standard Error: 1_466 + .saturating_add(Weight::from_ref_time(47_371).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/centrifuge/src/weights/pallet_restricted_tokens.rs b/runtime/centrifuge/src/weights/pallet_restricted_tokens.rs index faa6e9a628..22124344e3 100644 --- a/runtime/centrifuge/src/weights/pallet_restricted_tokens.rs +++ b/runtime/centrifuge/src/weights/pallet_restricted_tokens.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_restricted_tokens` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,79 +31,125 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_restricted_tokens`. pub struct WeightInfo(PhantomData); impl pallet_restricted_tokens::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_native() -> Weight { - // Minimum execution time: 62_747 nanoseconds. - Weight::from_ref_time(63_639_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 54_401 nanoseconds. + Weight::from_parts(54_932_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_other() -> Weight { - // Minimum execution time: 66_894 nanoseconds. - Weight::from_ref_time(68_538_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 56_395 nanoseconds. + Weight::from_parts(56_996_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_native() -> Weight { - // Minimum execution time: 56_746 nanoseconds. - Weight::from_ref_time(57_618_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 47_158 nanoseconds. + Weight::from_parts(48_039_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_other() -> Weight { - // Minimum execution time: 63_339 nanoseconds. - Weight::from_ref_time(64_150_000) + // Proof Size summary in bytes: + // Measured: `438` + // Estimated: `7811` + // Minimum execution time: 52_206 nanoseconds. + Weight::from_parts(53_319_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_native() -> Weight { - // Minimum execution time: 65_873 nanoseconds. - Weight::from_ref_time(67_386_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 57_527 nanoseconds. + Weight::from_parts(58_819_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_other() -> Weight { - // Minimum execution time: 70_582 nanoseconds. - Weight::from_ref_time(72_405_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 59_250 nanoseconds. + Weight::from_parts(60_302_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_native() -> Weight { - // Minimum execution time: 62_456 nanoseconds. - Weight::from_ref_time(63_569_000) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 53_970 nanoseconds. + Weight::from_parts(54_811_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_other() -> Weight { - // Minimum execution time: 67_957 nanoseconds. - Weight::from_ref_time(68_938_000) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 55_873 nanoseconds. + Weight::from_parts(57_136_000, 7811) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_native() -> Weight { - // Minimum execution time: 67_135 nanoseconds. - Weight::from_ref_time(68_308_000) + // Proof Size summary in bytes: + // Measured: `89` + // Estimated: `2603` + // Minimum execution time: 51_626 nanoseconds. + Weight::from_parts(53_179_000, 2603) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:1 w:1) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_other() -> Weight { - // Minimum execution time: 78_677 nanoseconds. - Weight::from_ref_time(80_440_000) + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `7731` + // Minimum execution time: 69_349 nanoseconds. + Weight::from_parts(70_301_000, 7731) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/runtime/centrifuge/src/weights/pallet_scheduler.rs b/runtime/centrifuge/src/weights/pallet_scheduler.rs index 3cb5b621d9..9d56d8aa9d 100644 --- a/runtime/centrifuge/src/weights/pallet_scheduler.rs +++ b/runtime/centrifuge/src/weights/pallet_scheduler.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_scheduler` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,96 +31,145 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_scheduler`. pub struct WeightInfo(PhantomData); impl pallet_scheduler::WeightInfo for WeightInfo { - // Storage: Scheduler IncompleteSince (r:1 w:1) + /// Storage: Scheduler IncompleteSince (r:1 w:1) + /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { - // Minimum execution time: 6_813 nanoseconds. - Weight::from_ref_time(7_073_000) + // Proof Size summary in bytes: + // Measured: `31` + // Estimated: `499` + // Minimum execution time: 5_630 nanoseconds. + Weight::from_parts(5_811_000, 499) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 50]`. fn service_agenda_base(s: u32, ) -> Weight { - // Minimum execution time: 6_352 nanoseconds. - Weight::from_ref_time(10_374_951) - // Standard Error: 4_153 - .saturating_add(Weight::from_ref_time(946_946).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 5_410 nanoseconds. + Weight::from_parts(8_102_685, 41438) + // Standard Error: 4_303 + .saturating_add(Weight::from_ref_time(1_192_507).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } fn service_task_base() -> Weight { - // Minimum execution time: 15_028 nanoseconds. - Weight::from_ref_time(15_368_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_666 nanoseconds. + Weight::from_ref_time(8_957_000) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - // Minimum execution time: 33_272 nanoseconds. - Weight::from_ref_time(33_442_000) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(1_424).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `245 + s * (1 ±0)` + // Estimated: `5286 + s * (1 ±0)` + // Minimum execution time: 28_773 nanoseconds. + Weight::from_parts(29_204_000, 5286) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_091).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) } - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn service_task_named() -> Weight { - // Minimum execution time: 18_054 nanoseconds. - Weight::from_ref_time(18_514_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_931 nanoseconds. + Weight::from_ref_time(11_271_000) .saturating_add(T::DbWeight::get().writes(1)) } fn service_task_periodic() -> Weight { - // Minimum execution time: 15_118 nanoseconds. - Weight::from_ref_time(15_489_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_656 nanoseconds. + Weight::from_ref_time(8_896_000) } fn execute_dispatch_signed() -> Weight { - // Minimum execution time: 6_893 nanoseconds. - Weight::from_ref_time(7_244_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_338 nanoseconds. + Weight::from_ref_time(4_539_000) } fn execute_dispatch_unsigned() -> Weight { - // Minimum execution time: 7_124 nanoseconds. - Weight::from_ref_time(7_263_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_248 nanoseconds. + Weight::from_ref_time(4_498_000) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 49]`. fn schedule(s: u32, ) -> Weight { - // Minimum execution time: 27_221 nanoseconds. - Weight::from_ref_time(32_180_333) - // Standard Error: 4_773 - .saturating_add(Weight::from_ref_time(973_849).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 19_406 nanoseconds. + Weight::from_parts(22_600_153, 41438) + // Standard Error: 3_883 + .saturating_add(Weight::from_ref_time(1_218_595).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `s` is `[1, 50]`. fn cancel(s: u32, ) -> Weight { - // Minimum execution time: 32_801 nanoseconds. - Weight::from_ref_time(31_787_843) - // Standard Error: 4_881 - .saturating_add(Weight::from_ref_time(1_668_745).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 25_216 nanoseconds. + Weight::from_parts(22_494_611, 41438) + // Standard Error: 5_203 + .saturating_add(Weight::from_ref_time(2_198_733).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[0, 49]`. fn schedule_named(s: u32, ) -> Weight { - // Minimum execution time: 31_759 nanoseconds. - Weight::from_ref_time(36_544_372) - // Standard Error: 4_280 - .saturating_add(Weight::from_ref_time(1_027_164).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `287 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 24_385 nanoseconds. + Weight::from_parts(28_285_732, 43961) + // Standard Error: 4_563 + .saturating_add(Weight::from_ref_time(1_241_067).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { - // Minimum execution time: 34_805 nanoseconds. - Weight::from_ref_time(34_921_065) - // Standard Error: 5_504 - .saturating_add(Weight::from_ref_time(1_702_088).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `313 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 27_231 nanoseconds. + Weight::from_parts(25_659_328, 43961) + // Standard Error: 5_187 + .saturating_add(Weight::from_ref_time(2_210_158).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/centrifuge/src/weights/pallet_session.rs b/runtime/centrifuge/src/weights/pallet_session.rs index 258d4c6c76..bca728fa42 100644 --- a/runtime/centrifuge/src/weights/pallet_session.rs +++ b/runtime/centrifuge/src/weights/pallet_session.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,19 +31,29 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:1 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:1 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { - // Minimum execution time: 39_403 nanoseconds. - Weight::from_ref_time(40_656_000) + // Proof Size summary in bytes: + // Measured: `369` + // Estimated: `5688` + // Minimum execution time: 26_319 nanoseconds. + Weight::from_parts(26_960_000, 5688) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:0 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { - // Minimum execution time: 31_740 nanoseconds. - Weight::from_ref_time(32_821_000) + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `3311` + // Minimum execution time: 19_136 nanoseconds. + Weight::from_parts(19_627_000, 3311) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/runtime/centrifuge/src/weights/pallet_timestamp.rs b/runtime/centrifuge/src/weights/pallet_timestamp.rs index ce2846d5a6..3ad903c802 100644 --- a/runtime/centrifuge/src/weights/pallet_timestamp.rs +++ b/runtime/centrifuge/src/weights/pallet_timestamp.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,16 +31,24 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - // Storage: Timestamp Now (r:1 w:1) - // Storage: Aura CurrentSlot (r:1 w:0) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Aura CurrentSlot (r:1 w:0) + /// Proof: Aura CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { - // Minimum execution time: 15_549 nanoseconds. - Weight::from_ref_time(16_200_000) + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `1006` + // Minimum execution time: 13_505 nanoseconds. + Weight::from_parts(14_156_000, 1006) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { - // Minimum execution time: 6_532 nanoseconds. + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `0` + // Minimum execution time: 6_452 nanoseconds. Weight::from_ref_time(6_733_000) } } diff --git a/runtime/centrifuge/src/weights/pallet_treasury.rs b/runtime/centrifuge/src/weights/pallet_treasury.rs index c2bdfcfe80..3bae6e1a89 100644 --- a/runtime/centrifuge/src/weights/pallet_treasury.rs +++ b/runtime/centrifuge/src/weights/pallet_treasury.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_treasury` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -31,56 +32,87 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { fn spend() -> Weight { - // Minimum execution time: 351 nanoseconds. - Weight::from_ref_time(390_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 311 nanoseconds. + Weight::from_ref_time(391_000) } - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { - // Minimum execution time: 44_282 nanoseconds. - Weight::from_ref_time(44_803_000) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `499` + // Minimum execution time: 33_593 nanoseconds. + Weight::from_parts(35_014_000, 499) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Treasury Proposals (r:1 w:1) - // Storage: System Account (r:2 w:2) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { - // Minimum execution time: 62_507 nanoseconds. - Weight::from_ref_time(64_340_000) + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `7789` + // Minimum execution time: 51_636 nanoseconds. + Weight::from_parts(52_649_000, 7789) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Treasury Proposals (r:1 w:0) - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - // Minimum execution time: 17_072 nanoseconds. - Weight::from_ref_time(21_055_504) - // Standard Error: 1_544 - .saturating_add(Weight::from_ref_time(78_818).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `501 + p * (8 ±0)` + // Estimated: `3480` + // Minimum execution time: 14_577 nanoseconds. + Weight::from_parts(18_158_350, 3480) + // Standard Error: 1_368 + .saturating_add(Weight::from_ref_time(53_682).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { - // Minimum execution time: 13_745 nanoseconds. - Weight::from_ref_time(14_146_000) + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `897` + // Minimum execution time: 11_231 nanoseconds. + Weight::from_parts(11_522_000, 897) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: System Account (r:1 w:0) - // Storage: Treasury Deactivated (r:1 w:1) - // Storage: Balances InactiveIssuance (r:1 w:1) - // Storage: Treasury Approvals (r:1 w:1) - // Storage: Treasury Proposals (r:2 w:0) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:100 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - // Minimum execution time: 53_910 nanoseconds. - Weight::from_ref_time(52_858_985) - // Standard Error: 5_402 - .saturating_add(Weight::from_ref_time(3_526_768).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `290 + p * (151 ±0)` + // Estimated: `4522 + p * (2583 ±0)` + // Minimum execution time: 41_407 nanoseconds. + Weight::from_parts(39_128_676, 4522) + // Standard Error: 7_831 + .saturating_add(Weight::from_ref_time(3_744_536).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2583).saturating_mul(p.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_uniques.rs b/runtime/centrifuge/src/weights/pallet_uniques.rs index 9feb52dc4a..a5198896e8 100644 --- a/runtime/centrifuge/src/weights/pallet_uniques.rs +++ b/runtime/centrifuge/src/weights/pallet_uniques.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,242 +31,387 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_uniques`. pub struct WeightInfo(PhantomData); impl pallet_uniques::WeightInfo for WeightInfo { - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 45_845 nanoseconds. - Weight::from_ref_time(47_319_000) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2657` + // Minimum execution time: 37_099 nanoseconds. + Weight::from_parts(38_051_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn force_create() -> Weight { - // Minimum execution time: 29_836 nanoseconds. - Weight::from_ref_time(30_587_000) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2657` + // Minimum execution time: 22_001 nanoseconds. + Weight::from_parts(23_043_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:1 w:0) - // Storage: Uniques ClassAccount (r:0 w:1) - // Storage: Uniques Attribute (r:0 w:1000) - // Storage: Uniques ClassMetadataOf (r:0 w:1) - // Storage: Uniques InstanceMetadataOf (r:0 w:1000) - // Storage: Uniques CollectionMaxSupply (r:0 w:1) - // Storage: Uniques Account (r:0 w:20) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1001 w:1000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:0 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:0 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1000) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:0 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 3_070_788 nanoseconds. - Weight::from_ref_time(3_128_347_000) - // Standard Error: 29_523 - .saturating_add(Weight::from_ref_time(12_987_083).saturating_mul(n.into())) - // Standard Error: 29_523 - .saturating_add(Weight::from_ref_time(131_912).saturating_mul(m.into())) - // Standard Error: 29_523 - .saturating_add(Weight::from_ref_time(617_852).saturating_mul(a.into())) + // Proof Size summary in bytes: + // Measured: `543 + n * (121 ±0) + m * (69 ±0) + a * (346 ±0)` + // Estimated: `5270 + n * (2613 ±0)` + // Minimum execution time: 3_092_729 nanoseconds. + Weight::from_parts(3_157_930_000, 5270) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(13_415_711).saturating_mul(n.into())) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(79_883).saturating_mul(m.into())) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(754_538).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(n.into())) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques CollectionMaxSupply (r:1 w:0) - // Storage: Uniques Account (r:0 w:1) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:1 w:0) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn mint() -> Weight { - // Minimum execution time: 56_796 nanoseconds. - Weight::from_ref_time(58_509_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `7773` + // Minimum execution time: 44_463 nanoseconds. + Weight::from_parts(45_435_000, 7773) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:1) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn burn() -> Weight { - // Minimum execution time: 59_191 nanoseconds. - Weight::from_ref_time(60_573_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 45_465 nanoseconds. + Weight::from_parts(46_346_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Account (r:0 w:2) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 47_118 nanoseconds. - Weight::from_ref_time(48_060_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 36_708 nanoseconds. + Weight::from_parts(37_470_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:102 w:102) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:5000 w:5000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 30_426 nanoseconds. - Weight::from_ref_time(31_008_000) - // Standard Error: 13_948 - .saturating_add(Weight::from_ref_time(18_779_545).saturating_mul(i.into())) + // Proof Size summary in bytes: + // Measured: `852 + i * (121 ±0)` + // Estimated: `2657 + i * (2613 ±0)` + // Minimum execution time: 20_338 nanoseconds. + Weight::from_parts(20_619_000, 2657) + // Standard Error: 17_567 + .saturating_add(Weight::from_ref_time(20_039_440).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(i.into())) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn freeze() -> Weight { - // Minimum execution time: 35_106 nanoseconds. - Weight::from_ref_time(36_338_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 25_197 nanoseconds. + Weight::from_parts(25_948_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn thaw() -> Weight { - // Minimum execution time: 35_356 nanoseconds. - Weight::from_ref_time(36_208_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 24_816 nanoseconds. + Weight::from_parts(25_767_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn freeze_collection() -> Weight { - // Minimum execution time: 28_803 nanoseconds. - Weight::from_ref_time(29_595_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_244 nanoseconds. + Weight::from_parts(19_156_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn thaw_collection() -> Weight { - // Minimum execution time: 28_654 nanoseconds. - Weight::from_ref_time(29_465_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_525 nanoseconds. + Weight::from_parts(18_986_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:2) + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:2) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // Minimum execution time: 39_624 nanoseconds. - Weight::from_ref_time(40_766_000) + // Proof Size summary in bytes: + // Measured: `463` + // Estimated: `5188` + // Minimum execution time: 29_224 nanoseconds. + Weight::from_parts(29_855_000, 5188) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Uniques Class (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn set_team() -> Weight { - // Minimum execution time: 29_756 nanoseconds. - Weight::from_ref_time(30_617_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 19_226 nanoseconds. + Weight::from_parts(19_677_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) fn force_item_status() -> Weight { - // Minimum execution time: 32_741 nanoseconds. - Weight::from_ref_time(33_473_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 22_912 nanoseconds. + Weight::from_parts(23_554_000, 2657) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // Minimum execution time: 69_009 nanoseconds. - Weight::from_ref_time(70_342_000) + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `8543` + // Minimum execution time: 52_367 nanoseconds. + Weight::from_parts(53_359_000, 8543) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // Minimum execution time: 67_686 nanoseconds. - Weight::from_ref_time(68_849_000) + // Proof Size summary in bytes: + // Measured: `1501` + // Estimated: `8543` + // Minimum execution time: 50_173 nanoseconds. + Weight::from_parts(51_286_000, 8543) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // Minimum execution time: 52_819 nanoseconds. - Weight::from_ref_time(54_021_000) + // Proof Size summary in bytes: + // Measured: `451` + // Estimated: `5463` + // Minimum execution time: 37_420 nanoseconds. + Weight::from_parts(38_081_000, 5463) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // Minimum execution time: 53_129 nanoseconds. - Weight::from_ref_time(55_113_000) + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `5463` + // Minimum execution time: 38_371 nanoseconds. + Weight::from_parts(39_043_000, 5463) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // Minimum execution time: 51_346 nanoseconds. - Weight::from_ref_time(52_558_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5431` + // Minimum execution time: 36_998 nanoseconds. + Weight::from_parts(37_570_000, 5431) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 49_763 nanoseconds. - Weight::from_ref_time(50_755_000) + // Proof Size summary in bytes: + // Measured: `740` + // Estimated: `5431` + // Minimum execution time: 35_075 nanoseconds. + Weight::from_parts(35_977_000, 5431) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // Minimum execution time: 36_208 nanoseconds. - Weight::from_ref_time(37_470_000) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 25_527 nanoseconds. + Weight::from_parts(26_119_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Asset (r:1 w:1) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // Minimum execution time: 36_538 nanoseconds. - Weight::from_ref_time(37_109_000) + // Proof Size summary in bytes: + // Measured: `612` + // Estimated: `5270` + // Minimum execution time: 25_638 nanoseconds. + Weight::from_parts(25_979_000, 5270) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // Minimum execution time: 33_102 nanoseconds. - Weight::from_ref_time(34_224_000) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2531` + // Minimum execution time: 20_518 nanoseconds. + Weight::from_parts(20_939_000, 2531) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques CollectionMaxSupply (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) + /// Storage: Uniques CollectionMaxSupply (r:1 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 32_060 nanoseconds. - Weight::from_ref_time(32_661_000) + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5160` + // Minimum execution time: 21_870 nanoseconds. + Weight::from_parts(22_752_000, 5160) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:0) - // Storage: Uniques ItemPriceOf (r:0 w:1) + /// Storage: Uniques Asset (r:1 w:0) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn set_price() -> Weight { - // Minimum execution time: 32_230 nanoseconds. - Weight::from_ref_time(32_891_000) + // Proof Size summary in bytes: + // Measured: `374` + // Estimated: `2613` + // Minimum execution time: 21_751 nanoseconds. + Weight::from_parts(22_431_000, 2613) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Uniques Asset (r:1 w:1) - // Storage: Uniques ItemPriceOf (r:1 w:1) - // Storage: Uniques Class (r:1 w:0) - // Storage: Uniques Account (r:0 w:2) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:1 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) fn buy_item() -> Weight { - // Minimum execution time: 62_176 nanoseconds. - Weight::from_ref_time(62_977_000) + // Proof Size summary in bytes: + // Measured: `739` + // Estimated: `7850` + // Minimum execution time: 51_215 nanoseconds. + Weight::from_parts(52_518_000, 7850) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/runtime/centrifuge/src/weights/pallet_utility.rs b/runtime/centrifuge/src/weights/pallet_utility.rs index 37a701bf71..b12401b8be 100644 --- a/runtime/centrifuge/src/weights/pallet_utility.rs +++ b/runtime/centrifuge/src/weights/pallet_utility.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -32,31 +33,46 @@ pub struct WeightInfo(PhantomData); impl pallet_utility::WeightInfo for WeightInfo { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - // Minimum execution time: 19_477 nanoseconds. - Weight::from_ref_time(28_446_071) - // Standard Error: 1_850 - .saturating_add(Weight::from_ref_time(6_945_253).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_209 nanoseconds. + Weight::from_ref_time(9_129_306) + // Standard Error: 2_960 + .saturating_add(Weight::from_ref_time(8_226_140).saturating_mul(c.into())) } fn as_derivative() -> Weight { - // Minimum execution time: 15_478 nanoseconds. - Weight::from_ref_time(16_180_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_564 nanoseconds. + Weight::from_ref_time(8_155_000) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - // Minimum execution time: 26_960 nanoseconds. - Weight::from_ref_time(192_961_427) - // Standard Error: 31_408 - .saturating_add(Weight::from_ref_time(7_054_942).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_599 nanoseconds. + Weight::from_ref_time(16_307_821) + // Standard Error: 3_188 + .saturating_add(Weight::from_ref_time(8_619_470).saturating_mul(c.into())) } fn dispatch_as() -> Weight { - // Minimum execution time: 22_652 nanoseconds. - Weight::from_ref_time(23_264_000) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_976 nanoseconds. + Weight::from_ref_time(14_467_000) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - // Minimum execution time: 19_066 nanoseconds. - Weight::from_ref_time(24_975_936) - // Standard Error: 1_708 - .saturating_add(Weight::from_ref_time(6_937_256).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_249 nanoseconds. + Weight::from_ref_time(6_571_875) + // Standard Error: 3_073 + .saturating_add(Weight::from_ref_time(8_206_947).saturating_mul(c.into())) } } diff --git a/runtime/centrifuge/src/weights/pallet_vesting.rs b/runtime/centrifuge/src/weights/pallet_vesting.rs index 23cc4714ca..3909302f87 100644 --- a/runtime/centrifuge/src/weights/pallet_vesting.rs +++ b/runtime/centrifuge/src/weights/pallet_vesting.rs @@ -2,7 +2,8 @@ //! Autogenerated weights for `pallet_vesting` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 @@ -30,107 +31,159 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_vesting`. pub struct WeightInfo(PhantomData); impl pallet_vesting::WeightInfo for WeightInfo { - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 3]`. fn vest_locked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 55_423 nanoseconds. - Weight::from_ref_time(53_829_320) - // Standard Error: 8_078 - .saturating_add(Weight::from_ref_time(132_613).saturating_mul(l.into())) - // Standard Error: 154_785 - .saturating_add(Weight::from_ref_time(1_131_683).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `331 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `6406` + // Minimum execution time: 35_025 nanoseconds. + Weight::from_parts(36_030_255, 6406) + // Standard Error: 1_480 + .saturating_add(Weight::from_ref_time(45_905).saturating_mul(l.into())) + // Standard Error: 28_359 + .saturating_add(Weight::from_ref_time(272_959).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 3]`. - fn vest_unlocked(_l: u32, _s: u32, ) -> Weight { - // Minimum execution time: 55_945 nanoseconds. - Weight::from_ref_time(62_151_915) + fn vest_unlocked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `331 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `6406` + // Minimum execution time: 35_816 nanoseconds. + Weight::from_parts(36_422_112, 6406) + // Standard Error: 1_586 + .saturating_add(Weight::from_ref_time(38_024).saturating_mul(l.into())) + // Standard Error: 30_391 + .saturating_add(Weight::from_ref_time(247_015).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 3]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 56_074 nanoseconds. - Weight::from_ref_time(57_182_642) - // Standard Error: 6_993 - .saturating_add(Weight::from_ref_time(65_210).saturating_mul(l.into())) - // Standard Error: 133_998 - .saturating_add(Weight::from_ref_time(497_377).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `466 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_183 nanoseconds. + Weight::from_parts(39_397_996, 9009) + // Standard Error: 3_031 + .saturating_add(Weight::from_ref_time(50_274).saturating_mul(l.into())) + // Standard Error: 58_087 + .saturating_add(Weight::from_ref_time(343_961).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 3]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 55_995 nanoseconds. - Weight::from_ref_time(57_007_876) - // Standard Error: 2_246 - .saturating_add(Weight::from_ref_time(66_416).saturating_mul(l.into())) - // Standard Error: 43_051 - .saturating_add(Weight::from_ref_time(200_190).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `466 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `9009` + // Minimum execution time: 38_331 nanoseconds. + Weight::from_parts(40_150_426, 9009) + // Standard Error: 3_074 + .saturating_add(Weight::from_ref_time(40_543).saturating_mul(l.into())) + // Standard Error: 58_899 + .saturating_add(Weight::from_ref_time(202_467).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 2]`. fn vested_transfer(_l: u32, _s: u32, ) -> Weight { - // Minimum execution time: 79_779 nanoseconds. - Weight::from_ref_time(96_339_407) + // Proof Size summary in bytes: + // Measured: `0 + l * (25 ±0) + s * (332 ±0)` + // Estimated: `9009` + // Minimum execution time: 59_550 nanoseconds. + Weight::from_parts(75_086_515, 9009) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 2]`. fn force_vested_transfer(_l: u32, _s: u32, ) -> Weight { - // Minimum execution time: 80_540 nanoseconds. - Weight::from_ref_time(94_270_513) + // Proof Size summary in bytes: + // Measured: `120 + l * (25 ±0) + s * (332 ±0)` + // Estimated: `11612` + // Minimum execution time: 63_668 nanoseconds. + Weight::from_parts(79_421_584, 11612) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 3]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // Minimum execution time: 56_555 nanoseconds. - Weight::from_ref_time(58_622_710) - // Standard Error: 3_005 - .saturating_add(Weight::from_ref_time(73_760).saturating_mul(l.into())) - // Standard Error: 95_845 - .saturating_add(Weight::from_ref_time(423_219).saturating_mul(s.into())) + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_253 nanoseconds. + Weight::from_parts(41_451_758, 9009) + // Standard Error: 3_869 + .saturating_add(Weight::from_ref_time(42_606).saturating_mul(l.into())) + // Standard Error: 123_401 + .saturating_add(Weight::from_ref_time(240_899).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 3]`. - fn unlocking_merge_schedules(l: u32, _s: u32, ) -> Weight { - // Minimum execution time: 57_297 nanoseconds. - Weight::from_ref_time(62_337_094) - // Standard Error: 9_491 - .saturating_add(Weight::from_ref_time(21_561).saturating_mul(l.into())) + fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_083 nanoseconds. + Weight::from_parts(41_148_427, 9009) + // Standard Error: 4_532 + .saturating_add(Weight::from_ref_time(43_606).saturating_mul(l.into())) + // Standard Error: 144_557 + .saturating_add(Weight::from_ref_time(368_102).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/runtime/centrifuge/src/xcm.rs b/runtime/centrifuge/src/xcm.rs index 95a8afaeca..e5b787f423 100644 --- a/runtime/centrifuge/src/xcm.rs +++ b/runtime/centrifuge/src/xcm.rs @@ -11,29 +11,34 @@ // GNU General Public License for more details. use cfg_primitives::{ - constants::currency_decimals, parachains, types::{EnsureRootOr, HalfOfCouncil}, }; +use cfg_traits::TryConvert; pub use cfg_types::tokens::CurrencyId; +use cfg_types::EVMChainId; pub use cumulus_primitives_core::ParaId; pub use frame_support::{ parameter_types, traits::{Contains, Everything, Get, Nothing}, weights::Weight, }; -use frame_support::{sp_std::marker::PhantomData, traits::fungibles}; +use frame_support::{ + sp_std::marker::PhantomData, + traits::{fungibles, fungibles::Mutate}, +}; use orml_asset_registry::{AssetRegistryTrader, FixedRateAssetRegistryTrader}; -use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; use orml_xcm_support::MultiNativeAsset; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use runtime_common::{ - xcm::{general_key, AccountIdToMultiLocation, FixedConversionRateProvider}, - xcm_fees::{default_per_second, native_per_second}, + xcm::{general_key, AccountIdToMultiLocation, FixedConversionRateProvider, LpInstanceRelayer}, + xcm_fees::native_per_second, }; use sp_core::ConstU32; use sp_runtime::traits::{Convert, Zero}; +pub use xcm::v3::{MultiAsset, MultiLocation}; use xcm::{prelude::*, v3::Weight as XcmWeight}; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, @@ -45,10 +50,41 @@ use xcm_builder::{ use xcm_executor::{traits::JustTry, XcmExecutor}; use super::{ - AccountId, Balance, OrmlAssetRegistry, OrmlTokens, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, + AccountId, Balance, OrmlAssetRegistry, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, }; +/// A call filter for the XCM Transact instruction. This is a temporary +/// measure until we properly account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call +/// parameters. +/// +/// NOTE: Defensive configuration for now, inspired by filter of +/// SystemParachains and Polkadot, can be extended if desired. +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::Timestamp(..) + | RuntimeCall::Balances(..) + | RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) + | RuntimeCall::PolkadotXcm( + pallet_xcm::Call::limited_reserve_transfer_assets { .. } + ) | RuntimeCall::XcmpQueue(..) + | RuntimeCall::DmpQueue(..) + | RuntimeCall::Proxy(..) + | RuntimeCall::LiquidityPoolsGateway( + pallet_liquidity_pools_gateway::Call::process_msg { .. } + ) // TODO: Enable later: | RuntimeCall::OrderBook(..) + ) + } +} + /// The main XCM config /// This is where we configure the core of our XCM integrations: how tokens are /// transferred, how fees are calculated, what barriers we impose on incoming @@ -72,7 +108,7 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = crate::AllPalletsWithSystem; type ResponseHandler = PolkadotXcm; type RuntimeCall = RuntimeCall; - type SafeCallFilter = Everything; + type SafeCallFilter = SafeCallFilter; type SubscriptionService = PolkadotXcm; type Trader = Trader; type UniversalAliases = Nothing; @@ -103,26 +139,6 @@ parameter_types! { native_per_second(), 0, ); - - pub CfgPerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2(Parachain(ParachainInfo::parachain_id().into()), general_key(parachains::polkadot::centrifuge::CFG_KEY)), - ).into(), - native_per_second(), - ); - - pub AUSDPerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2( - Parachain(parachains::polkadot::acala::ID), - general_key(parachains::polkadot::acala::AUSD_KEY) - ) - ).into(), - default_per_second(currency_decimals::AUSD) - ); - } pub struct ToTreasury; @@ -138,7 +154,7 @@ impl TakeRevenue for ToTreasury { if let Ok(currency_id) = >::convert(location) { - let _ = OrmlTokens::deposit(currency_id, &TreasuryAccount::get(), amount); + let _ = Tokens::mint_into(currency_id, &TreasuryAccount::get(), amount); } } } @@ -218,10 +234,12 @@ impl xcm_executor::traits::Convert for CurrencyIdConv let unanchored_location = match location { MultiLocation { parents: 0, - interior: X1(x), + interior, } => MultiLocation { parents: 1, - interior: X2(Parachain(u32::from(ParachainInfo::get())), x), + interior: interior + .pushed_front_with(Parachain(u32::from(ParachainInfo::get()))) + .map_err(|_| location)?, }, x => x, }; @@ -263,7 +281,7 @@ impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type SendXcmOrigin = EnsureXcmOrigin; - type SovereignAccountOf = (); + type SovereignAccountOf = LocationToAccountId; type TrustedLockers = (); type UniversalLocation = UniversalLocation; type Weigher = FixedWeightBounds; @@ -295,6 +313,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Generate remote accounts according to polkadot standards + cfg_primitives::xcm::HashedDescriptionDescribeFamilyAllTerminal, ); /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -309,11 +329,31 @@ pub type XcmRouter = ( XcmpQueue, ); +const MOONBEAM_PARA_ID: u32 = 2004; +/// https://chainlist.org/chain/1284 +const MOONBEAM_EVM_ID: u64 = 1284; + +/// A constant way of mapping parachain IDs to EVM-chain IDs +pub struct ParaToEvm; +impl TryConvert for ParaToEvm { + type Error = cfg_types::ParaId; + + fn try_convert(a: cfg_types::ParaId) -> Result { + // NOTE: Currently only supported moonbeam + match a { + MOONBEAM_PARA_ID => Ok(MOONBEAM_EVM_ID), + _ => Err(a), + } + } +} + /// This is the type we use to convert an (incoming) XCM origin into a local -/// `RuntimeOrigin` instance, ready for dispatching a transaction with Xcm's +/// `Origin` instance, ready for dispatching a transaction with Xcm's /// `Transact`. There is an `OriginKind` which can biases the kind of local -/// `RuntimeOrigin` it will become. +/// `Origin` it will become. pub type XcmOriginToTransactDispatchOrigin = ( + // A matcher that catches all Moonbeam relaying contracts to generate the right Origin + LpInstanceRelayer, // Sovereign account converter; this attempts to derive an `AccountId` from the origin location // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for // foreign chains who want to have a local sovereign account on this chain which they control. diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index a228f150c8..8e64162621 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -13,13 +13,13 @@ smallvec = "1.6.1" # Substrate dependencies codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } - frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-treasury = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +parachain-info = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.38" } +scale-info = { version = "2.3.0", default-features = false, features = ["derive"] } sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -27,9 +27,12 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", default-features sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } # Polkadot dependencies +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } # ORML dependencies +orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } @@ -63,6 +66,7 @@ pallet-anchors = { path = "../../pallets/anchors", default-features = false } pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-liquidity-pools = { path = "../../pallets/liquidity-pools", default-features = false } +pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway", default-features = false } pallet-loans = { path = "../../pallets/loans", default-features = false } pallet-pool-system = { path = "../../pallets/pool-system", default-features = false } @@ -71,7 +75,9 @@ log = "0.4" sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } [dev-dependencies] -hex-literal = "0.2.1" +cfg-mocks = { path = "../../libs/mocks", features = ["runtime-benchmarks", "std"] } +hex-literal = "0.3.4" +pallet-collective = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = true, branch = "polkadot-v0.9.38" } [features] @@ -89,6 +95,7 @@ std = [ "pallet-evm-chain-id/std", "pallet-evm-precompile-dispatch/std", "pallet-liquidity-pools/std", + "pallet-liquidity-pools-gateway/std", "pallet-treasury/std", "sp-core/std", "sp-api/std", @@ -103,6 +110,7 @@ std = [ "frame-system/std", "cfg-primitives/std", "cfg-utils/std", + "orml-asset-registry/std", "orml-traits/std", "cfg-traits/std", "pallet-loans/std", @@ -121,6 +129,9 @@ std = [ "pallet-evm-precompile-sha3fips/std", "pallet-evm-precompile-simple/std", "pallet-investments/std", + "xcm-executor/std", + "parachain-info/std", + "polkadot-parachain/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", @@ -132,6 +143,7 @@ runtime-benchmarks = [ "pallet-anchors/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-liquidity-pools/runtime-benchmarks", + "pallet-liquidity-pools-gateway/runtime-benchmarks", "pallet-pool-system/runtime-benchmarks", "pallet-loans/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", @@ -142,6 +154,9 @@ runtime-benchmarks = [ "xcm-primitives/runtime-benchmarks", "axelar-gateway-precompile/runtime-benchmarks", "pallet-investments/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", + "orml-asset-registry/runtime-benchmarks", + "polkadot-parachain/runtime-benchmarks", ] on-chain-release-build = [ @@ -159,6 +174,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-liquidity-pools/try-runtime", + "pallet-liquidity-pools-gateway/try-runtime", "pallet-pool-system/try-runtime", "pallet-loans/try-runtime", "pallet-data-collector/try-runtime", @@ -172,4 +188,6 @@ try-runtime = [ "fp-self-contained/try-runtime", "axelar-gateway-precompile/try-runtime", "pallet-investments/try-runtime", + "parachain-info/try-runtime", + "orml-asset-registry/try-runtime", ] diff --git a/runtime/common/src/account_conversion.rs b/runtime/common/src/account_conversion.rs index f5cfb4ca38..714fe0a6ab 100644 --- a/runtime/common/src/account_conversion.rs +++ b/runtime/common/src/account_conversion.rs @@ -11,16 +11,18 @@ // GNU General Public License for more details. use cfg_primitives::AccountId; +use cfg_traits::TryConvert; use cfg_types::domain_address::{Domain, DomainAddress}; use pallet_evm::AddressMapping; use sp_core::{Get, H160}; use sp_runtime::traits::Convert; +use xcm::*; /// Common converter code for translating accounts across different /// domains and chains. -pub struct AccountConverter(core::marker::PhantomData); +pub struct AccountConverter(core::marker::PhantomData<(R, XcmConverter)>); -impl AccountConverter { +impl AccountConverter { /// Converts an EVM address from a given chain into a local AccountId pub fn convert_evm_address(chain_id: u64, address: [u8; 20]) -> AccountId { // We use a custom encoding here rather than relying on @@ -40,7 +42,7 @@ impl AccountConverter { } // Implement EVM account conversion using our shared conversion code -impl AddressMapping for AccountConverter +impl AddressMapping for AccountConverter where R: pallet_evm_chain_id::Config, { @@ -51,7 +53,7 @@ where } // Implement liquidityPools account conversion using our shared conversion code -impl Convert for AccountConverter { +impl Convert for AccountConverter { fn convert(domain_address: DomainAddress) -> AccountId { match domain_address { DomainAddress::Centrifuge(addr) => AccountId::new(addr), @@ -60,7 +62,7 @@ impl Convert for AccountConverter { } } -impl Convert<(Domain, [u8; 32]), AccountId> for AccountConverter { +impl Convert<(Domain, [u8; 32]), AccountId> for AccountConverter { fn convert((domain, account): (Domain, [u8; 32])) -> AccountId { match domain { Domain::Centrifuge => AccountId::new(account), @@ -73,6 +75,33 @@ impl Convert<(Domain, [u8; 32]), AccountId> for AccountConverter { } } } +impl TryConvert for AccountConverter +where + XcmConverter: xcm_executor::traits::Convert, +{ + type Error = v3::MultiLocation; + + fn try_convert(location: v3::MultiLocation) -> Result { + // Try xcm logic first + match XcmConverter::convert_ref(location).ok() { + Some(acc) => Ok(acc), + None => { + // match EVM logic + match location { + v3::MultiLocation { + parents: 0, + interior: + v3::Junctions::X1(v3::Junction::AccountKey20 { + network: Some(v3::NetworkId::Ethereum { chain_id }), + key, + }), + } => Ok(Self::convert_evm_address(chain_id, key)), + _ => Err(location), + } + } + } + } +} #[cfg(test)] mod tests { @@ -85,7 +114,7 @@ mod tests { let address = [0x42; 20]; let chain_id = 0xDADB0D; let domain_address = DomainAddress::EVM(chain_id, address); - let account: AccountId = AccountConverter::<()>::convert(domain_address); + let account: AccountId = AccountConverter::<(), ()>::convert(domain_address); let expected = AccountId::new(hex![ "42424242424242424242424242424242424242420000000000DADB0D45564d00" ]); @@ -98,7 +127,7 @@ mod tests { let address = [0x42; 32]; let expected = AccountId::new(address); let domain_address = DomainAddress::Centrifuge(address); - let account: AccountId = AccountConverter::<()>::convert(domain_address); + let account: AccountId = AccountConverter::<(), ()>::convert(domain_address); assert_eq!(account, expected); } diff --git a/runtime/common/src/apis/account_conversion.rs b/runtime/common/src/apis/account_conversion.rs new file mode 100644 index 0000000000..d89499c419 --- /dev/null +++ b/runtime/common/src/apis/account_conversion.rs @@ -0,0 +1,25 @@ +// 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 codec::Codec; +use sp_api::decl_runtime_apis; +use xcm::v3::MultiLocation; + +decl_runtime_apis! { + /// Runtime Api for the pallet-anchors, to be implemented + /// by and for a specific runtime that uses that pallet. + pub trait AccountConversionApi + where + AccountId: Codec + { + fn conversion_of(location: MultiLocation) -> Option; + } +} diff --git a/runtime/common/src/apis/mod.rs b/runtime/common/src/apis/mod.rs index 810bd7b330..58fda594d7 100644 --- a/runtime/common/src/apis/mod.rs +++ b/runtime/common/src/apis/mod.rs @@ -11,12 +11,14 @@ // GNU General Public License for more details. //! Runtime apis useful in the Centrifuge ecosystem +pub use account_conversion::*; pub use anchors::*; pub use investments::*; pub use loans::*; pub use pools::*; pub use rewards::*; +mod account_conversion; mod anchors; mod investments; mod loans; diff --git a/runtime/common/src/evm/precompile.rs b/runtime/common/src/evm/precompile.rs index d997e45443..cf0987f909 100644 --- a/runtime/common/src/evm/precompile.rs +++ b/runtime/common/src/evm/precompile.rs @@ -59,9 +59,10 @@ impl CentrifugePrecompiles { impl PrecompileSet for CentrifugePrecompiles where - R: pallet_evm::Config, + R: pallet_evm::Config + axelar_gateway_precompile::Config + frame_system::Config, R::RuntimeCall: Dispatchable + GetDispatchInfo + Decode, ::RuntimeOrigin: From>, + axelar_gateway_precompile::Pallet: Precompile, { fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { match handle.code_address().0 { @@ -77,6 +78,9 @@ where SHA3FIPS256_ADDR => Some(Sha3FIPS256::execute(handle)), DISPATCH_ADDR => Some(Dispatch::::execute(handle)), ECRECOVERPUBLICKEY_ADDR => Some(ECRecoverPublicKey::execute(handle)), + LP_AXELAR_GATEWAY => { + Some( as Precompile>::execute(handle)) + } _ => None, } } @@ -91,6 +95,7 @@ where | BN128PAIRING_ADDR | BLAKE2F_ADDR | SHA3FIPS256_ADDR | DISPATCH_ADDR | ECRECOVERPUBLICKEY_ADDR + | LP_AXELAR_GATEWAY ) } } diff --git a/runtime/common/src/gateway.rs b/runtime/common/src/gateway.rs new file mode 100644 index 0000000000..b82249b63a --- /dev/null +++ b/runtime/common/src/gateway.rs @@ -0,0 +1,37 @@ +// Copyright 2023 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_primitives::AccountId; +use pallet_evm::AddressMapping; +use polkadot_parachain::primitives::Sibling; +use sp_core::{crypto::AccountId32, Get, H160}; +use sp_runtime::traits::AccountIdConversion; + +use crate::account_conversion::AccountConverter; + +pub struct GatewayAccountProvider(core::marker::PhantomData<(T, XcmConverter)>); + +impl GatewayAccountProvider +where + T: pallet_evm_chain_id::Config + parachain_info::Config, + XcmConverter: xcm_executor::traits::Convert, +{ + pub fn get_gateway_account() -> AccountId { + let sender_account: AccountId = + Sibling::from(parachain_info::Pallet::::get()).into_account_truncating(); + + let truncated_sender_account = + H160::from_slice(&>::as_ref(&sender_account)[0..20]); + + AccountConverter::::into_account_id(truncated_sender_account) + } +} diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 33e26ada59..417c21113e 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -21,8 +21,10 @@ mod tests; pub mod account_conversion; pub mod apis; pub mod evm; +pub mod gateway; pub mod migrations; pub mod oracle; +pub mod xcm; #[macro_export] macro_rules! production_or_benchmark { @@ -227,68 +229,6 @@ pub mod asset_registry { } } -pub mod xcm { - use cfg_primitives::types::Balance; - use cfg_types::tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}; - use frame_support::sp_std::marker::PhantomData; - use sp_runtime::traits::Convert; - use xcm::{ - latest::{Junction::GeneralKey, MultiLocation}, - prelude::{AccountId32, X1}, - }; - - use crate::xcm_fees::default_per_second; - - /// Our FixedConversionRateProvider, used to charge XCM-related fees for - /// tokens registered in the asset registry that were not already handled by - /// native Trader rules. - pub struct FixedConversionRateProvider(PhantomData); - - impl< - OrmlAssetRegistry: orml_traits::asset_registry::Inspect< - AssetId = CurrencyId, - Balance = Balance, - CustomMetadata = CustomMetadata, - >, - > orml_traits::FixedConversionRateProvider for FixedConversionRateProvider - { - fn get_fee_per_second(location: &MultiLocation) -> Option { - let metadata = OrmlAssetRegistry::metadata_by_location(location)?; - match metadata.additional.transferability { - CrossChainTransferability::Xcm(xcm_metadata) - | CrossChainTransferability::All(xcm_metadata) => xcm_metadata - .fee_per_second - .or_else(|| Some(default_per_second(metadata.decimals))), - _ => None, - } - } - } - - /// A utils function to un-bloat and simplify the instantiation of - /// `GeneralKey` values - pub fn general_key(data: &[u8]) -> xcm::latest::Junction { - GeneralKey { - length: data.len().min(32) as u8, - data: cfg_utils::vec_to_fixed_array(data.to_vec()), - } - } - - /// How we convert an `[AccountId]` into an XCM MultiLocation - pub struct AccountIdToMultiLocation(PhantomData); - impl Convert for AccountIdToMultiLocation - where - AccountId: Into<[u8; 32]>, - { - fn convert(account: AccountId) -> MultiLocation { - X1(AccountId32 { - network: None, - id: account.into(), - }) - .into() - } - } -} - pub mod changes { use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; @@ -550,3 +490,201 @@ pub mod foreign_investments { } } } + +pub mod origin { + use cfg_primitives::AccountId; + use frame_support::traits::{EitherOfDiverse, SortedMembers}; + use frame_system::{EnsureRoot, EnsureSignedBy}; + use sp_core::Get; + + pub type EnsureAccountOrRoot = + EitherOfDiverse, AccountId>, EnsureRoot>; + + pub type EnsureAccountOrRootOr = EitherOfDiverse, O>; + + pub struct AdminOnly(sp_std::marker::PhantomData); + + impl SortedMembers for AdminOnly + where + Account: Get, + { + fn sorted_members() -> sp_std::vec::Vec { + sp_std::vec![Account::get()] + } + } + + #[cfg(test)] + mod test { + use cfg_primitives::HalfOfCouncil; + use frame_support::traits::EnsureOrigin; + use sp_core::{crypto::AccountId32, parameter_types}; + + use super::*; + + parameter_types! { + pub Admin: AccountId = AccountId::new([0u8;32]); + } + + #[derive(Clone)] + enum OuterOrigin { + Raw(frame_system::RawOrigin), + Council(pallet_collective::RawOrigin), + Dummy, + } + + impl Into, OuterOrigin>> for OuterOrigin { + fn into(self) -> Result, OuterOrigin> { + match self { + Self::Raw(raw) => Ok(raw), + _ => Err(self), + } + } + } + + impl + Into< + Result< + pallet_collective::RawOrigin< + sp_runtime::AccountId32, + pallet_collective::Instance1, + >, + OuterOrigin, + >, + > for OuterOrigin + { + fn into( + self, + ) -> Result< + pallet_collective::RawOrigin, + OuterOrigin, + > { + match self { + Self::Council(raw) => Ok(raw), + _ => Err(self), + } + } + } + + impl From> for OuterOrigin { + fn from(value: frame_system::RawOrigin) -> Self { + Self::Raw(value) + } + } + + impl From> for OuterOrigin { + fn from( + value: pallet_collective::RawOrigin, + ) -> Self { + Self::Council(value) + } + } + + mod ensure_account_or_root_or { + use super::*; + + #[test] + fn works_with_account() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::Signed(Admin::get())); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_ok() + ) + } + + #[test] + fn fails_with_non_admin_account() { + let origin = + OuterOrigin::Raw(frame_system::RawOrigin::Signed(AccountId::from([1u8; 32]))); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_err() + ) + } + + #[test] + fn works_with_half_of_council() { + let origin = OuterOrigin::Council(pallet_collective::RawOrigin::Members(5, 9)); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_ok() + ) + } + + #[test] + fn fails_with_less_than_half_of_council() { + let origin = OuterOrigin::Council(pallet_collective::RawOrigin::Members(4, 9)); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_err() + ) + } + + #[test] + fn works_with_root() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::Root); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_ok() + ) + } + + #[test] + fn fails_with_none() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::None); + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_err() + ) + } + + #[test] + fn fails_with_dummy() { + let origin = OuterOrigin::Dummy; + + assert!( + EnsureAccountOrRootOr::::ensure_origin(origin).is_err() + ) + } + } + + mod ensure_account_or_root { + use super::*; + + #[test] + fn works_with_account() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::Signed(Admin::get())); + + assert!(EnsureAccountOrRoot::::ensure_origin(origin).is_ok()) + } + + #[test] + fn fails_with_non_admin_account() { + let origin = + OuterOrigin::Raw(frame_system::RawOrigin::Signed(AccountId::from([1u8; 32]))); + + assert!(EnsureAccountOrRoot::::ensure_origin(origin).is_err()) + } + + #[test] + fn works_with_root() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::Root); + + assert!(EnsureAccountOrRoot::::ensure_origin(origin).is_ok()) + } + + #[test] + fn fails_with_none() { + let origin = OuterOrigin::Raw(frame_system::RawOrigin::None); + + assert!(EnsureAccountOrRoot::::ensure_origin(origin).is_err()) + } + + #[test] + fn fails_with_dummy() { + let origin = OuterOrigin::Dummy; + + assert!(EnsureAccountOrRoot::::ensure_origin(origin).is_err()) + } + } + } +} diff --git a/runtime/common/src/migrations/asset_registry_xcmv3.rs b/runtime/common/src/migrations/asset_registry_xcmv3.rs new file mode 100644 index 0000000000..5b10f12dad --- /dev/null +++ b/runtime/common/src/migrations/asset_registry_xcmv3.rs @@ -0,0 +1,235 @@ +// Copyright 2023 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 cfg_primitives::Balance; +use cfg_types::tokens::{CurrencyId, CustomMetadata}; +#[cfg(feature = "try-runtime")] +use codec::Encode; +use frame_support::{ + traits::OnRuntimeUpgrade, + weights::{constants::RocksDbWeight, Weight}, + StoragePrefixedMap, +}; +use orml_traits::asset_registry::AssetMetadata; +#[cfg(feature = "try-runtime")] +use sp_arithmetic::traits::Zero; +use sp_std::vec::Vec; + +pub struct Migration< + T, + Assets, + const EXPECTED_MAINNET_LOC_COUNT: u32, + const EXPECTED_MAINNET_META_COUNT: u32, + const EXPECTED_TESTNET_LOC_COUNT: u32, + const EXPECTED_TESTNET_META_COUNT: u32, +>(sp_std::marker::PhantomData<(T, Assets)>); + +impl< + T, + Assets, + const EXPECTED_MAINNET_LOC_COUNT: u32, + const EXPECTED_MAINNET_META_COUNT: u32, + const EXPECTED_TESTNET_LOC_COUNT: u32, + const EXPECTED_TESTNET_META_COUNT: u32, + > OnRuntimeUpgrade + for Migration< + T, + Assets, + EXPECTED_MAINNET_LOC_COUNT, + EXPECTED_MAINNET_META_COUNT, + EXPECTED_TESTNET_LOC_COUNT, + EXPECTED_TESTNET_META_COUNT, + > where + T: orml_asset_registry::Config, + ::Balance: From, + ::CustomMetadata: From, + ::AssetId: From, + AssetMetadata< + ::Balance, + ::CustomMetadata, + >: From>, + Assets: AssetsToMigrate, +{ + fn on_runtime_upgrade() -> Weight { + log::info!("💎 AssetRegistryMultilocationToXCMV3: on_runtime_upgrade: started"); + // Complexity: 2 reads + let (loc_count, meta_count) = Self::get_key_counts(); + + // Complexity: O(loc_count) writes + let result = orml_asset_registry::LocationToAssetId::::clear(loc_count, None); + match result.maybe_cursor { + None => log::info!("💎 AssetRegistryMultilocationToXCMV3: Cleared all LocationToAssetId entries successfully"), + Some(_) => { + log::error!( + "💎 AssetRegistryMultilocationToXCMV3: LocationToAssetId not fully cleared: {:?} remaining", + orml_asset_registry::LocationToAssetId::::iter_keys().count() + ) + } + } + log::info!( + "💎 AssetRegistryMultilocationToXCMV3: LocationToAssetId clearing iteration result. backend: {} unique: {} loops: {}", + result.backend, + result.unique, + result.loops, + ); + + // Complexity: O(meta_count) writes + let result = orml_asset_registry::Metadata::::clear(meta_count, None); + match result.maybe_cursor { + None => log::info!("Cleared all Metadata entries successfully"), + Some(_) => log::error!("Metadata not fully cleared"), + } + log::info!( + "💎 AssetRegistryMultilocationToXCMV3: Metadata clearing iteration result. backend: {} unique: {} loops: {}", + result.backend, + result.unique, + result.loops, + ); + + log::info!( + "💎 AssetRegistryMultilocationToXCMV3: Starting migration of {:?} assets", + Assets::get_assets_to_migrate(loc_count, meta_count) + .iter() + .len() + ); + // Complexity: O(meta_count + loc_count) writes + Assets::get_assets_to_migrate(loc_count, meta_count) + .into_iter() + .for_each(|(asset_id, asset_metadata)| { + log::debug!("Migrating asset: {:?}", asset_id); + orml_asset_registry::Pallet::::do_register_asset_without_asset_processor( + asset_metadata.into(), + asset_id.into(), + ) + .map_err(|e| log::error!("Failed to register asset id: {:?}", e)) + .ok(); + }); + + log::info!("💎 AssetRegistryMultilocationToXCMV3: on_runtime_upgrade: completed!"); + RocksDbWeight::get().reads_writes( + 2, + loc_count + .saturating_add(meta_count) + .saturating_mul(2) + .into(), + ) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + log::info!("💎 AssetRegistryMultilocationToXCMV3: pre-upgrade: started"); + let (loc_count, meta_count) = Self::get_key_counts(); + + match (loc_count, meta_count) { + (loc, meta) + if (loc, meta) == (EXPECTED_MAINNET_LOC_COUNT, EXPECTED_MAINNET_META_COUNT) => + { + Ok(()) + } + (loc, meta) + if (loc, meta) == (EXPECTED_TESTNET_LOC_COUNT, EXPECTED_TESTNET_META_COUNT) => + { + Ok(()) + } + _ => Err("💎 AssetRegistryMultilocationToXCMV3: Unexpected counters"), + }?; + + log::info!("💎 AssetRegistryMultilocationToXCMV3: pre-upgrade: done"); + Ok((loc_count, meta_count).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_old_counts: Vec) -> Result<(), &'static str> { + log::info!("💎 AssetRegistryMultilocationToXCMV3: post-upgrade: started"); + let (loc_count, meta_count) = Self::get_key_counts(); + + // Should not check for strict equality as at least the location count is + // expected to have increased + // * For Centrifuge we can check post_upgrade >= pre_upgrade + // * For Altair, we remove one of the two AUSD variants and thus have less + // registered currencies + assert!(!loc_count.is_zero()); + assert!(!meta_count.is_zero()); + + log::info!("💎 AssetRegistryMultilocationToXCMV3: post_upgrade: storage was updated!"); + Ok(()) + } +} + +impl< + T: orml_asset_registry::Config, + AssetsToMigrate, + const EXPECTED_MAINNET_LOC_COUNT: u32, + const EXPECTED_MAINNET_META_COUNT: u32, + const EXPECTED_TESTNET_LOC_COUNT: u32, + const EXPECTED_TESTNET_META_COUNT: u32, + > + Migration< + T, + AssetsToMigrate, + EXPECTED_MAINNET_LOC_COUNT, + EXPECTED_MAINNET_META_COUNT, + EXPECTED_TESTNET_LOC_COUNT, + EXPECTED_TESTNET_META_COUNT, + > +{ + fn get_key_counts() -> (u32, u32) { + // let loc_count = + // orml_asset_registry::LocationToAssetId::::iter_keys().count() as u32; + // let meta_count = orml_asset_registry::Metadata::::iter_keys().count() as + // u32; + let loc_count = Self::count_storage_keys( + orml_asset_registry::LocationToAssetId::::final_prefix().as_ref(), + ); + let meta_count = + Self::count_storage_keys(orml_asset_registry::Metadata::::final_prefix().as_ref()); + + log::info!( + "💎 AssetRegistryMultilocationToXCMV3: Found {} LocationToAssetId keys ", + loc_count + ); + log::info!( + "💎 AssetRegistryMultilocationToXCMV3: Found {} Metadata keys ", + meta_count + ); + + (loc_count, meta_count) + } + + pub fn count_storage_keys(prefix: &[u8]) -> u32 { + let mut count = 0; + let mut next_key = prefix.to_vec(); + loop { + match sp_io::storage::next_key(&next_key) { + Some(key) if !key.starts_with(prefix) => break count, + Some(key) => { + next_key = key; + count += 1; + } + None => { + break count; + } + } + } + } +} + +pub trait AssetsToMigrate { + fn get_assets_to_migrate( + loc_count: u32, + meta_count: u32, + ) -> Vec<( + CurrencyId, + orml_asset_registry::AssetMetadata, + )>; +} diff --git a/runtime/common/src/migrations/mod.rs b/runtime/common/src/migrations/mod.rs index 2485686f5b..e48a109a0b 100644 --- a/runtime/common/src/migrations/mod.rs +++ b/runtime/common/src/migrations/mod.rs @@ -12,4 +12,5 @@ //! Centrifuge Runtime-Common Migrations +pub mod asset_registry_xcmv3; pub mod nuke; diff --git a/runtime/common/src/migrations/nuke.rs b/runtime/common/src/migrations/nuke.rs index c37023f997..e712f03b2e 100644 --- a/runtime/common/src/migrations/nuke.rs +++ b/runtime/common/src/migrations/nuke.rs @@ -51,10 +51,13 @@ where "Pallet is already updated" ); - ensure!( - unhashed::contains_prefixed_key(&pallet_prefix::()), - "Pallet prefix doesn't exists" - ); + // NOTE: We still want to be able to bump StorageVersion + if !unhashed::contains_prefixed_key(&pallet_prefix::()) { + log::info!( + "Nuke-{}: Pallet prefix doesn't exist, storage is empty already", + Pallet::name(), + ) + } Ok(Vec::new()) } @@ -96,7 +99,7 @@ where + DbWeight::get().reads_writes(1, 1) // Version read & writen } else { log::warn!( - "Nuke-{}: pallet on-chain version is not {:?}. This upgrade can be removed.", + "Nuke-{}: pallet on-chain version is not less than {:?}. This upgrade can be removed.", Pallet::name(), Pallet::current_storage_version() ); diff --git a/runtime/common/src/xcm.rs b/runtime/common/src/xcm.rs new file mode 100644 index 0000000000..29f88c37cc --- /dev/null +++ b/runtime/common/src/xcm.rs @@ -0,0 +1,440 @@ +// 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 cfg_primitives::types::Balance; +use cfg_traits::TryConvert; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, + EVMChainId, ParaId, +}; +use frame_support::sp_std::marker::PhantomData; +use sp_runtime::traits::Convert; +use xcm::v3::{ + Junction::{AccountId32, AccountKey20, GeneralKey, Parachain}, + Junctions::{X1, X2}, + MultiLocation, OriginKind, +}; + +use crate::xcm_fees::default_per_second; + +/// Our FixedConversionRateProvider, used to charge XCM-related fees for +/// tokens registered in the asset registry that were not already handled by +/// native Trader rules. +pub struct FixedConversionRateProvider(PhantomData); + +impl< + OrmlAssetRegistry: orml_traits::asset_registry::Inspect< + AssetId = CurrencyId, + Balance = Balance, + CustomMetadata = CustomMetadata, + >, + > orml_traits::FixedConversionRateProvider for FixedConversionRateProvider +{ + fn get_fee_per_second(location: &MultiLocation) -> Option { + let metadata = OrmlAssetRegistry::metadata_by_location(location)?; + match metadata.additional.transferability { + CrossChainTransferability::Xcm(xcm_metadata) + | CrossChainTransferability::All(xcm_metadata) => xcm_metadata + .fee_per_second + .or_else(|| Some(default_per_second(metadata.decimals))), + _ => None, + } + } +} + +/// A utils function to un-bloat and simplify the instantiation of +/// `GeneralKey` values +pub fn general_key(data: &[u8]) -> xcm::latest::Junction { + GeneralKey { + length: data.len().min(32) as u8, + data: cfg_utils::vec_to_fixed_array(data.to_vec()), + } +} + +/// How we convert an `[AccountId]` into an XCM MultiLocation +pub struct AccountIdToMultiLocation(PhantomData); +impl Convert for AccountIdToMultiLocation +where + AccountId: Into<[u8; 32]>, +{ + fn convert(account: AccountId) -> MultiLocation { + X1(AccountId32 { + network: None, + id: account.into(), + }) + .into() + } +} + +pub struct LpInstanceRelayer(PhantomData<(ParaAsEvmChain, Runtime)>); +impl + xcm_executor::traits::ConvertOrigin<::RuntimeOrigin> + for LpInstanceRelayer +where + ParaAsEvmChain: TryConvert, + Runtime: pallet_liquidity_pools_gateway::Config, + ::RuntimeOrigin: + From, +{ + fn convert_origin( + origin: impl Into, + kind: OriginKind, + ) -> Result<::RuntimeOrigin, MultiLocation> { + let location: MultiLocation = origin.into(); + match kind { + OriginKind::SovereignAccount => match location { + MultiLocation { + parents: 1, + interior: X2(Parachain(para), AccountKey20 { key, .. }), + } => { + let evm_id = ParaAsEvmChain::try_convert(para).map_err(|_| location)?; + let domain_address = DomainAddress::EVM(evm_id, key); + + if pallet_liquidity_pools_gateway::Pallet::::relayer( + Domain::EVM(evm_id), + &domain_address, + ) + .is_some() + { + Ok(pallet_liquidity_pools_gateway::GatewayOrigin::AxelarRelay( + domain_address, + ) + .into()) + } else { + Err(location) + } + } + _ => Err(location), + }, + _ => Err(location), + } + } +} + +#[cfg(test)] +mod test { + use cfg_mocks::{ + pallet_mock_liquidity_pools, pallet_mock_routers, pallet_mock_try_convert, MessageMock, + RouterMock, + }; + use frame_support::{assert_ok, traits::EnsureOrigin}; + use frame_system::EnsureRoot; + use pallet_liquidity_pools_gateway::{EnsureLocal, GatewayOrigin}; + use sp_core::{ConstU16, ConstU32, ConstU64, H256}; + use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + DispatchError, + }; + use xcm_executor::traits::ConvertOrigin; + + use super::*; + + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + type Block = frame_system::mocking::MockBlock; + type AccountId = u64; + + pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into() + } + + // For testing the pallet, we construct a mock runtime. + frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Gateway: pallet_liquidity_pools_gateway, + MockLP: pallet_mock_liquidity_pools, + MockParaAsEvmChain: pallet_mock_try_convert::, + MockOriginRecovery: pallet_mock_try_convert::, + } + ); + + impl frame_system::Config for Runtime { + type AccountData = (); + type AccountId = AccountId; + type BaseCallFilter = frame_support::traits::Everything; + type BlockHashCount = ConstU64<250>; + type BlockLength = (); + type BlockNumber = u64; + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Header = Header; + type Index = u64; + type Lookup = IdentityLookup; + type MaxConsumers = ConstU32<16>; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); + } + + impl pallet_mock_try_convert::Config for Runtime { + type Error = (); + type From = ParaId; + type To = EVMChainId; + } + + impl pallet_mock_try_convert::Config for Runtime { + type Error = DispatchError; + type From = (Vec, Vec); + type To = DomainAddress; + } + + impl pallet_mock_liquidity_pools::Config for Runtime { + type DomainAddress = DomainAddress; + type Message = MessageMock; + } + + impl pallet_mock_routers::Config for Runtime {} + + impl pallet_liquidity_pools_gateway::Config for Runtime { + type AdminOrigin = EnsureRoot; + type InboundQueue = MockLP; + type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; + type MaxIncomingMessageSize = ConstU32<1024>; + type Message = MessageMock; + type OriginRecovery = MockOriginRecovery; + type Router = RouterMock; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type Sender = ConstU64<11>; + type WeightInfo = (); + } + + const RELAYER_PARA_ID: u32 = 1000; + const RELAYER_EVM_ID: u64 = 1001; + const RELAYER_ADDRESS: [u8; 20] = [1u8; 20]; + + #[test] + fn lp_instance_relayer_converts_correctly() { + new_test_ext().execute_with(|| { + let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); + + assert_ok!(Gateway::add_relayer( + RuntimeOrigin::root(), + expected_address.clone(), + )); + + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, RELAYER_PARA_ID); + Ok(RELAYER_EVM_ID) + }); + + let location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(RELAYER_PARA_ID), + AccountKey20 { + network: None, + key: RELAYER_ADDRESS, + }, + ), + ); + + let origin = LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .expect("Origin conversion failed unexpectedly."); + + assert_eq!( + EnsureLocal::ensure_origin(origin).expect("Generate origin must be GatewayOrigin"), + GatewayOrigin::AxelarRelay(expected_address) + ) + }) + } + + #[test] + fn lp_instance_relayer_fails_with_wrong_location() { + new_test_ext().execute_with(|| { + let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); + + assert_ok!(Gateway::add_relayer( + RuntimeOrigin::root(), + expected_address.clone(), + )); + + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, RELAYER_PARA_ID); + Ok(RELAYER_EVM_ID) + }); + + let location: MultiLocation = MultiLocation::new(1, X1(Parachain(RELAYER_PARA_ID))); + + assert_eq!( + LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .unwrap_err(), + location + ); + }) + } + + #[test] + fn lp_instance_relayer_fails_if_relayer_not_set() { + new_test_ext().execute_with(|| { + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, RELAYER_PARA_ID); + Ok(RELAYER_EVM_ID) + }); + + let location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(RELAYER_PARA_ID), + AccountKey20 { + network: None, + key: RELAYER_ADDRESS, + }, + ), + ); + + assert_eq!( + LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .unwrap_err(), + location + ); + }) + } + + #[test] + fn lp_instance_relayer_fails_if_para_to_evm_fails() { + new_test_ext().execute_with(|| { + let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); + + assert_ok!(Gateway::add_relayer( + RuntimeOrigin::root(), + expected_address.clone(), + )); + + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, RELAYER_PARA_ID); + Err(()) + }); + + let location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(RELAYER_PARA_ID), + AccountKey20 { + network: None, + key: RELAYER_ADDRESS, + }, + ), + ); + + assert_eq!( + LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .unwrap_err(), + location + ); + }) + } + + #[test] + fn lp_instance_relayer_fails_if_wrong_para() { + new_test_ext().execute_with(|| { + let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); + + assert_ok!(Gateway::add_relayer( + RuntimeOrigin::root(), + expected_address.clone(), + )); + + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, 1); + Err(()) + }); + + let location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(1), + AccountKey20 { + network: None, + key: RELAYER_ADDRESS, + }, + ), + ); + + assert_eq!( + LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .unwrap_err(), + location + ); + }) + } + + #[test] + fn lp_instance_relayer_fails_if_wrong_address() { + new_test_ext().execute_with(|| { + let expected_address = DomainAddress::EVM(RELAYER_EVM_ID, RELAYER_ADDRESS); + + assert_ok!(Gateway::add_relayer( + RuntimeOrigin::root(), + expected_address.clone(), + )); + + MockParaAsEvmChain::mock_try_convert(|from| { + assert_eq!(from, RELAYER_PARA_ID); + Ok(RELAYER_EVM_ID) + }); + + let location: MultiLocation = MultiLocation::new( + 1, + X2( + Parachain(RELAYER_PARA_ID), + AccountKey20 { + network: None, + key: [0u8; 20], + }, + ), + ); + + assert_eq!( + LpInstanceRelayer::::convert_origin( + location, + OriginKind::SovereignAccount, + ) + .unwrap_err(), + location + ); + }) + } +} diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index 37740b4213..83512c9575 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "development-runtime" -version = "0.10.20" +version = "0.10.21" authors = ["Centrifuge "] edition = "2021" build = "build.rs" @@ -157,6 +157,7 @@ default = ["std"] instant-voting = [] fast-runtime = [] std = [ + "axelar-gateway-precompile/std", "cfg-primitives/std", "cfg-types/std", "chainbridge/std", @@ -274,10 +275,10 @@ std = [ "fp-self-contained/std", "moonbeam-relay-encoder/std", "getrandom/std", - "axelar-gateway-precompile/std", ] runtime-benchmarks = [ + "axelar-gateway-precompile/runtime-benchmarks", "cfg-types/runtime-benchmarks", "chainbridge/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", @@ -346,12 +347,12 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-primitives/runtime-benchmarks", - "axelar-gateway-precompile/runtime-benchmarks", "pallet-claims/runtime-benchmarks", "pallet-rewards/runtime-benchmarks", ] try-runtime = [ + "axelar-gateway-precompile/try-runtime", "cfg-primitives/try-runtime", "cfg-traits/try-runtime", "cfg-primitives/try-runtime", @@ -435,7 +436,6 @@ try-runtime = [ "fp-self-contained/try-runtime", "runtime-common/try-runtime", "sp-runtime/try-runtime", - "axelar-gateway-precompile/try-runtime", ] # A feature that should be enabled when the runtime should be build for on-chain diff --git a/runtime/development/src/evm.rs b/runtime/development/src/evm.rs index 7e526efbd5..2a1c0856f6 100644 --- a/runtime/development/src/evm.rs +++ b/runtime/development/src/evm.rs @@ -22,7 +22,7 @@ use sp_core::{crypto::ByteArray, H160, U256}; use sp_runtime::Permill; use sp_std::marker::PhantomData; -use crate::{Aura, Runtime, RuntimeEvent}; +use crate::{Aura, LocationToAccountId, Runtime, RuntimeEvent}; // To create valid Ethereum-compatible blocks, we need a 20-byte // "author" for the block. Since that author is purely informational, @@ -48,7 +48,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { - type AddressMapping = AccountConverter; + type AddressMapping = AccountConverter; type BlockGasLimit = BlockGasLimit; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressTruncated; @@ -86,11 +86,10 @@ impl pallet_ethereum::Config for Runtime { type StateRoot = pallet_ethereum::IntermediateStateRoot; } -impl pallet_ethereum_transaction::Config for Runtime { - type RuntimeEvent = RuntimeEvent; -} +impl pallet_ethereum_transaction::Config for Runtime {} impl axelar_gateway_precompile::Config for Runtime { type AdminOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 15ae0dc9fc..7e6ffed66c 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -19,15 +19,13 @@ // Allow things like `1 * CFG` #![allow(clippy::identity_op)] -use ::xcm::latest::{MultiAsset, MultiLocation}; pub use cfg_primitives::{ constants::*, types::{PoolId, *}, }; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as _}, - CurrencyPrice, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, - PriceValue, TrancheTokenPrice, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, TryConvert as _, }; use cfg_types::{ consts::pools::*, @@ -140,7 +138,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1020, + spec_version: 1022, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -298,7 +296,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = Moment; type OnTimestampSet = Aura; - type WeightInfo = pallet_timestamp::weights::SubstrateWeight; + type WeightInfo = weights::pallet_timestamp::WeightInfo; } // money stuff @@ -402,7 +400,7 @@ impl pallet_multisig::Config for Runtime { type MaxSignatories = MaxSignatories; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_multisig::weights::SubstrateWeight; + type WeightInfo = weights::pallet_multisig::WeightInfo; } parameter_types! { @@ -614,14 +612,14 @@ impl pallet_proxy::Config for Runtime { type ProxyType = ProxyType; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type WeightInfo = weights::pallet_proxy::WeightInfo; } impl pallet_utility::Config for Runtime { type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_utility::weights::SubstrateWeight; + type WeightInfo = weights::pallet_utility::WeightInfo; } parameter_types! { @@ -641,7 +639,7 @@ impl pallet_scheduler::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type ScheduleOrigin = EnsureRoot; - type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type WeightInfo = weights::pallet_scheduler::WeightInfo; } parameter_types! { @@ -673,7 +671,7 @@ impl pallet_collective::Config for Runtime { type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; - type WeightInfo = pallet_collective::weights::SubstrateWeight; + type WeightInfo = weights::pallet_collective::WeightInfo; } parameter_types! { @@ -715,7 +713,7 @@ impl pallet_elections_phragmen::Config for Runtime { type VotingBondBase = VotingBondBase; /// How much should be locked up in order to be able to submit votes. type VotingBondFactor = VotingBond; - type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; + type WeightInfo = weights::pallet_elections_phragmen::WeightInfo; } #[cfg(feature = "instant-voting")] @@ -793,7 +791,7 @@ impl pallet_democracy::Config for Runtime { type VoteLockingPeriod = EnactmentPeriod; /// How often (in blocks) to check for new votes. type VotingPeriod = VotingPeriod; - type WeightInfo = pallet_democracy::weights::SubstrateWeight; + type WeightInfo = weights::pallet_democracy::WeightInfo; } parameter_types! { @@ -817,7 +815,7 @@ impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Slashed = (); type SubAccountDeposit = SubAccountDeposit; - type WeightInfo = pallet_identity::weights::SubstrateWeight; + type WeightInfo = weights::pallet_identity::WeightInfo; } parameter_types! { @@ -832,7 +830,7 @@ impl pallet_vesting::Config for Runtime { type MinVestedTransfer = MinVestedTransfer; type RuntimeEvent = RuntimeEvent; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - type WeightInfo = pallet_vesting::weights::SubstrateWeight; + type WeightInfo = weights::pallet_vesting::WeightInfo; const MAX_VESTING_SCHEDULES: u32 = 28; } @@ -871,7 +869,7 @@ impl pallet_uniques::Config for Runtime { type RuntimeEvent = RuntimeEvent; type StringLimit = Limit; type ValueLimit = Limit; - type WeightInfo = pallet_uniques::weights::SubstrateWeight; + type WeightInfo = weights::pallet_uniques::WeightInfo; } parameter_types! { @@ -937,7 +935,7 @@ impl pallet_treasury::Config for Runtime { type SpendFunds = (); type SpendOrigin = frame_support::traits::NeverEnsureOrigin; type SpendPeriod = SpendPeriod; - type WeightInfo = pallet_treasury::weights::SubstrateWeight; + type WeightInfo = weights::pallet_treasury::WeightInfo; } // our pallets @@ -965,7 +963,7 @@ impl pallet_anchors::Config for Runtime { type Currency = Balances; type Fees = Fees; type PreCommitDepositFeeKey = PreCommitDepositFeeKey; - type WeightInfo = (); + type WeightInfo = weights::pallet_anchors::WeightInfo; } impl pallet_collator_allowlist::Config for Runtime { @@ -1033,6 +1031,7 @@ parameter_types! { impl pallet_pool_system::Config for Runtime { type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; + type BalanceRatio = Quantity; type ChallengeTime = ChallengeTime; type Currency = Balances; type CurrencyId = CurrencyId; @@ -1081,7 +1080,6 @@ impl pallet_pool_registry::Config for Runtime { type Permission = Permissions; type PoolCreateOrigin = EnsureSigned; type PoolId = PoolId; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TrancheCurrency = TrancheCurrency; type TrancheId = TrancheId; @@ -1167,33 +1165,6 @@ impl PoolUpdateGuard for UpdateGuard { } } -pub struct CurrencyPriceSource; -impl CurrencyPrice for CurrencyPriceSource { - type Moment = Moment; - type Rate = Rate; - - fn get_latest( - base: CurrencyId, - quote: Option, - ) -> Option> { - match base { - CurrencyId::Tranche(pool_id, tranche_id) => { - match as TrancheTokenPrice< - AccountId, - CurrencyId, - >>::get(pool_id, tranche_id) - { - // If a specific quote is requested, this needs to match the actual quote. - Some(price) if Some(price.pair.quote) != quote => None, - Some(price) => Some(price), - None => None, - } - } - _ => None, - } - } -} - parameter_types! { pub const MigrationMaxAccounts: u32 = 100; pub const MigrationMaxVestings: u32 = 10; @@ -1370,7 +1341,7 @@ impl pallet_interest_accrual::Config for Runtime { type Rate = Rate; type RuntimeEvent = RuntimeEvent; type Time = Timestamp; - type Weights = (); + type Weights = weights::pallet_interest_accrual::WeightInfo; } impl pallet_loans::Config for Runtime { @@ -1594,6 +1565,7 @@ impl pallet_foreign_investments::Config for Runtime { type InvestmentId = TrancheCurrency; type PoolId = PoolId; type PoolInspect = PoolSystem; + // TODO: Switch to ratio after merging #1546 type Rate = Rate; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; @@ -1610,16 +1582,16 @@ impl pallet_liquidity_pools::Config for Runtime { type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; + type BalanceRatio = Quantity; type CurrencyId = CurrencyId; - type DomainAccountToAccountId = AccountConverter; - type DomainAddressToAccountId = AccountConverter; + type DomainAccountToAccountId = AccountConverter; + type DomainAddressToAccountId = AccountConverter; type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; type OutboundQueue = LiquidityPoolsGateway; type Permission = Permissions; type PoolId = PoolId; type PoolInspect = PoolSystem; - type Rate = Rate; type RuntimeEvent = RuntimeEvent; type Time = Timestamp; type Tokens = Tokens; @@ -1706,7 +1678,7 @@ parameter_types! { impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; - type BalanceRatio = Rate; + type BalanceRatio = Quantity; type CollectedInvestmentHook = pallet_foreign_investments::hooks::CollectedInvestmentHook; type CollectedRedemptionHook = @@ -1875,11 +1847,11 @@ impl pallet_transfer_allowlist::Config for Runtime { type Location = Location; type ReserveCurrency = Balances; type RuntimeEvent = RuntimeEvent; - type Weights = (); + type WeightInfo = weights::pallet_transfer_allowlist::WeightInfo; } parameter_types! { - pub const OrderPairVecSize: u32 = 1_000_000u32; + pub const OrderPairVecSize: u32 = 1_000u32; } impl pallet_order_book::Config for Runtime { @@ -1970,7 +1942,7 @@ construct_runtime!( // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 121, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Config, Event, Origin} = 121, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 122, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 123, XTokens: orml_xtokens::{Pallet, Storage, Call, Event} = 124, @@ -1989,7 +1961,7 @@ construct_runtime!( EVMChainId: pallet_evm_chain_id::{Pallet, Config, Storage} = 161, BaseFee: pallet_base_fee::{Pallet, Call, Config, Storage, Event} = 162, Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 163, - EthereumTransaction: pallet_ethereum_transaction::{Pallet, Storage, Event} = 164, + EthereumTransaction: pallet_ethereum_transaction::{Pallet, Storage} = 164, LiquidityPoolsAxelarGateway: axelar_gateway_precompile::{Pallet, Call, Storage, Event} = 165, // migration pallet @@ -2027,7 +1999,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type PriceForSiblingDelivery = (); type RuntimeEvent = RuntimeEvent; type VersionWrapper = PolkadotXcm; - type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; + type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type XcmExecutor = XcmExecutor; } @@ -2369,6 +2341,12 @@ impl_runtime_apis! { } } + impl runtime_common::apis::AccountConversionApi for Runtime { + fn conversion_of(location: MultiLocation) -> Option { + AccountConverter::::try_convert(location).ok() + } + } + // Frontier APIs impl fp_rpc::EthereumRuntimeRPCApi for Runtime { fn chain_id() -> u64 { @@ -2549,27 +2527,42 @@ impl_runtime_apis! { // It should be called Anchors to make the runtime_benchmarks.sh script works type Anchors = Anchor; + add_benchmark!(params, batches, frame_system, SystemBench::); + add_benchmark!(params, batches, pallet_timestamp, Timestamp); + add_benchmark!(params, batches, pallet_balances, Balances); + add_benchmark!(params, batches, pallet_multisig, Multisig); + add_benchmark!(params, batches, pallet_proxy, Proxy); + add_benchmark!(params, batches, pallet_utility, Utility); + add_benchmark!(params, batches, pallet_scheduler, Scheduler); + add_benchmark!(params, batches, pallet_collective, Council); + add_benchmark!(params, batches, pallet_democracy, Democracy); + add_benchmark!(params, batches, pallet_elections_phragmen, Elections); + add_benchmark!(params, batches, pallet_identity, Identity); + add_benchmark!(params, batches, pallet_vesting, Vesting); + add_benchmark!(params, batches, pallet_treasury, Treasury); + add_benchmark!(params, batches, pallet_preimage, Preimage); add_benchmark!(params, batches, pallet_fees, Fees); add_benchmark!(params, batches, pallet_anchors, Anchors); + add_benchmark!(params, batches, pallet_block_rewards, BlockRewards); add_benchmark!(params, batches, pallet_migration_manager, Migration); add_benchmark!(params, batches, pallet_crowdloan_claim, CrowdloanClaim); add_benchmark!(params, batches, pallet_crowdloan_reward, CrowdloanReward); add_benchmark!(params, batches, pallet_collator_allowlist, CollatorAllowlist); add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); - add_benchmark!(params, batches, pallet_permissions, Permissions); - add_benchmark!(params, batches, pallet_nft_sales, NftSales); - add_benchmark!(params, batches, pallet_balances, Balances); - add_benchmark!(params, batches, frame_system, SystemBench::); - add_benchmark!(params, batches, pallet_pool_system, PoolSystem); add_benchmark!(params, batches, pallet_pool_registry, PoolRegistry); - add_benchmark!(params, batches, pallet_loans, Loans); + add_benchmark!(params, batches, pallet_pool_system, PoolSystem); + add_benchmark!(params, batches, pallet_permissions, Permissions); add_benchmark!(params, batches, pallet_interest_accrual, InterestAccrual); + add_benchmark!(params, batches, pallet_uniques, Uniques); add_benchmark!(params, batches, pallet_keystore, Keystore); add_benchmark!(params, batches, pallet_restricted_tokens, Tokens); add_benchmark!(params, batches, pallet_session, SessionBench::); - add_benchmark!(params, batches, pallet_block_rewards, BlockRewards); + add_benchmark!(params, batches, pallet_loans, Loans); + add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); + add_benchmark!(params, batches, cumulus_pallet_xcmp_queue, XcmpQueue); add_benchmark!(params, batches, pallet_transfer_allowlist, TransferAllowList); add_benchmark!(params, batches, pallet_order_book, OrderBook); + add_benchmark!(params, batches, pallet_nft_sales, NftSales); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) @@ -2588,27 +2581,42 @@ impl_runtime_apis! { let mut list = Vec::::new(); + list_benchmark!(list, extra, frame_system, SystemBench::); + list_benchmark!(list, extra, pallet_timestamp, Timestamp); + list_benchmark!(list, extra, pallet_balances, Balances); + list_benchmark!(list, extra, pallet_multisig, Multisig); + list_benchmark!(list, extra, pallet_proxy, Proxy); + list_benchmark!(list, extra, pallet_utility, Utility); + list_benchmark!(list, extra, pallet_scheduler, Scheduler); + list_benchmark!(list, extra, pallet_collective, Council); + list_benchmark!(list, extra, pallet_democracy, Democracy); + list_benchmark!(list, extra, pallet_elections_phragmen, Elections); + list_benchmark!(list, extra, pallet_identity, Identity); + list_benchmark!(list, extra, pallet_vesting, Vesting); + list_benchmark!(list, extra, pallet_treasury, Treasury); + list_benchmark!(list, extra, pallet_preimage, Preimage); list_benchmark!(list, extra, pallet_fees, Fees); list_benchmark!(list, extra, pallet_anchors, Anchor); + list_benchmark!(list, extra, pallet_block_rewards, BlockRewards); list_benchmark!(list, extra, pallet_migration_manager, Migration); list_benchmark!(list, extra, pallet_crowdloan_claim, CrowdloanClaim); list_benchmark!(list, extra, pallet_crowdloan_reward, CrowdloanReward); list_benchmark!(list, extra, pallet_collator_allowlist, CollatorAllowlist); list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); - list_benchmark!(list, extra, pallet_permissions, Permissions); - list_benchmark!(list, extra, pallet_nft_sales, NftSales); - list_benchmark!(list, extra, pallet_balances, Balances); - list_benchmark!(list, extra, frame_system, SystemBench::); - list_benchmark!(list, extra, pallet_pool_system, PoolSystem); list_benchmark!(list, extra, pallet_pool_registry, PoolRegistry); - list_benchmark!(list, extra, pallet_loans, Loans); + list_benchmark!(list, extra, pallet_pool_system, PoolSystem); + list_benchmark!(list, extra, pallet_permissions, Permissions); list_benchmark!(list, extra, pallet_interest_accrual, InterestAccrual); + list_benchmark!(list, extra, pallet_session, SessionBench::); + list_benchmark!(list, extra, pallet_uniques, Uniques); list_benchmark!(list, extra, pallet_keystore, Keystore); list_benchmark!(list, extra, pallet_restricted_tokens, Tokens); - list_benchmark!(list, extra, pallet_session, SessionBench::); - list_benchmark!(list, extra, pallet_block_rewards, BlockRewards); + list_benchmark!(list, extra, pallet_loans, Loans); + list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); + list_benchmark!(list, extra, cumulus_pallet_xcmp_queue, XcmpQueue); list_benchmark!(list, extra, pallet_transfer_allowlist, TransferAllowList); list_benchmark!(list, extra, pallet_order_book, OrderBook); + list_benchmark!(list, extra, pallet_nft_sales, NftSales); let storage_info = AllPalletsWithSystem::storage_info(); diff --git a/runtime/development/src/liquidity_pools.rs b/runtime/development/src/liquidity_pools.rs index 7b4e18172b..c9dc2b9ff9 100644 --- a/runtime/development/src/liquidity_pools.rs +++ b/runtime/development/src/liquidity_pools.rs @@ -11,14 +11,17 @@ // GNU General Public License for more details. use cfg_primitives::{AccountId, Balance, PoolId, TrancheId}; -use cfg_types::{domain_address::Domain, fixed_point::Rate}; +use cfg_types::{domain_address::Domain, fixed_point::Quantity}; use frame_support::parameter_types; use frame_system::EnsureRoot; +use runtime_common::gateway::GatewayAccountProvider; use super::{Runtime, RuntimeEvent, RuntimeOrigin}; +use crate::LocationToAccountId; parameter_types! { pub const MaxIncomingMessageSize: u32 = 1024; + pub Sender: AccountId = GatewayAccountProvider::::get_gateway_account(); } impl pallet_liquidity_pools_gateway::Config for Runtime { @@ -26,9 +29,11 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type InboundQueue = crate::LiquidityPools; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; - type Message = pallet_liquidity_pools::Message; + type Message = pallet_liquidity_pools::Message; + type OriginRecovery = crate::LiquidityPoolsAxelarGateway; type Router = liquidity_pools_gateway_routers::DomainRouter; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; + type Sender = Sender; type WeightInfo = (); } diff --git a/runtime/development/src/weights/cumulus_pallet_xcmp_queue.rs b/runtime/development/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 0000000000..1bc93a4205 --- /dev/null +++ b/runtime/development/src/weights/cumulus_pallet_xcmp_queue.rs @@ -0,0 +1,56 @@ + +//! Autogenerated weights for `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=cumulus_pallet_xcmp_queue +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/cumulus_pallet_xcmp_queue.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `cumulus_pallet_xcmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { + /// Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Proof Skipped: XcmpQueue QueueConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_config_with_u32() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `637` + // Minimum execution time: 8_587 nanoseconds. + Weight::from_parts(9_057_000, 637) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: XcmpQueue QueueConfig (r:1 w:1) + /// Proof Skipped: XcmpQueue QueueConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_config_with_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `637` + // Minimum execution time: 8_636 nanoseconds. + Weight::from_parts(9_037_000, 637) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/development/src/weights/frame_system.rs b/runtime/development/src/weights/frame_system.rs index 100a7edafa..ef64d62f1b 100644 --- a/runtime/development/src/weights/frame_system.rs +++ b/runtime/development/src/weights/frame_system.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for frame_system + +//! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-15, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=frame_system @@ -16,52 +19,89 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/frame_system.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/frame_system.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for frame_system using the Substrate node and recommended hardware. +/// Weight functions for `frame_system`. pub struct WeightInfo(PhantomData); impl frame_system::WeightInfo for WeightInfo { - fn remark(b: u32) -> Weight { - Weight::from_ref_time(0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000).saturating_mul(b as u64)) + /// The range of component `b` is `[0, 3932160]`. + fn remark(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_065 nanoseconds. + Weight::from_ref_time(100_146_976) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(285).saturating_mul(b.into())) } - - fn remark_with_event(b: u32) -> Weight { - Weight::from_ref_time(0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(3_000).saturating_mul(b as u64)) + /// The range of component `b` is `[0, 3932160]`. + fn remark_with_event(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_241 nanoseconds. + Weight::from_ref_time(167_579_235) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_684).saturating_mul(b.into())) } - + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { - Weight::from_ref_time(9_000_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `495` + // Minimum execution time: 5_751 nanoseconds. + Weight::from_parts(6_092_000, 495) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - - fn set_storage(i: u32) -> Weight { - Weight::from_ref_time(0) // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(1_156_000).saturating_mul(i as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn set_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_965 nanoseconds. + Weight::from_ref_time(3_075_000) + // Standard Error: 1_718 + .saturating_add(Weight::from_ref_time(885_573).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - - fn kill_storage(i: u32) -> Weight { - Weight::from_ref_time(0) // Standard Error: 18_000 - .saturating_add(Weight::from_ref_time(866_000).saturating_mul(i as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(i as u64))) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn kill_storage(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_936 nanoseconds. + Weight::from_ref_time(3_055_000) + // Standard Error: 859 + .saturating_add(Weight::from_ref_time(638_231).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - - fn kill_prefix(p: u32) -> Weight { - Weight::from_ref_time(0) // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(2_099_000).saturating_mul(p as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// The range of component `p` is `[0, 1000]`. + fn kill_prefix(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `171 + p * (69 ±0)` + // Estimated: `148 + p * (70 ±0)` + // Minimum execution time: 5_992 nanoseconds. + Weight::from_parts(6_142_000, 148) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(1_283_958).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) } } diff --git a/runtime/development/src/weights/mod.rs b/runtime/development/src/weights/mod.rs index 52f54e076e..0f93b6023b 100644 --- a/runtime/development/src/weights/mod.rs +++ b/runtime/development/src/weights/mod.rs @@ -9,22 +9,39 @@ // 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 mod cumulus_pallet_xcmp_queue; pub mod frame_system; +pub mod pallet_anchors; pub mod pallet_balances; pub mod pallet_block_rewards; pub mod pallet_collator_allowlist; pub mod pallet_collator_selection; +pub mod pallet_collective; pub mod pallet_crowdloan_claim; pub mod pallet_crowdloan_reward; +pub mod pallet_democracy; +pub mod pallet_elections_phragmen; pub mod pallet_fees; +pub mod pallet_identity; +pub mod pallet_interest_accrual; pub mod pallet_keystore; pub mod pallet_loans; pub mod pallet_migration_manager; +pub mod pallet_multisig; pub mod pallet_nft_sales; pub mod pallet_order_book; pub mod pallet_permissions; pub mod pallet_pool_registry; pub mod pallet_pool_system; +pub mod pallet_preimage; +pub mod pallet_proxy; pub mod pallet_restricted_tokens; +pub mod pallet_scheduler; pub mod pallet_session; +pub mod pallet_timestamp; +pub mod pallet_transfer_allowlist; +pub mod pallet_treasury; +pub mod pallet_uniques; +pub mod pallet_utility; +pub mod pallet_vesting; pub mod pallet_xcm; diff --git a/runtime/development/src/weights/pallet_anchors.rs b/runtime/development/src/weights/pallet_anchors.rs new file mode 100644 index 0000000000..0682f97eac --- /dev/null +++ b/runtime/development/src/weights/pallet_anchors.rs @@ -0,0 +1,510 @@ + +//! Autogenerated weights for `pallet_anchors` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_anchors +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_anchors.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_anchors`. +pub struct WeightInfo(PhantomData); +impl pallet_anchors::WeightInfo for WeightInfo { + /// Storage: Anchor AnchorEvictDates (r:1 w:0) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + fn pre_commit() -> Weight { + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `7625` + // Minimum execution time: 34_143 nanoseconds. + Weight::from_parts(34_975_000, 7625) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:1 w:1) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Anchor PreCommits (r:1 w:1) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Fees FeeBalances (r:1 w:0) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Authorship Author (r:1 w:0) + /// Proof: Authorship Author (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: System Digest (r:1 w:0) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Anchor LatestAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:0 w:1) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) + /// Proof Skipped: unknown `0xdb4faa73ca6d2016e53c7156087c176b79b169c409b8a0063a07964f3187f9e9` (r:0 w:1) + fn commit() -> Weight { + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `11053` + // Minimum execution time: 64_680 nanoseconds. + Weight::from_parts(66_354_000, 11053) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: Anchor PreCommits (r:100 w:100) + /// Proof: Anchor PreCommits (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + fn evict_pre_commits() -> Weight { + // Proof Size summary in bytes: + // Measured: `15750` + // Estimated: `259100` + // Minimum execution time: 1_717_384 nanoseconds. + Weight::from_parts(1_729_056_000, 259100) + .saturating_add(T::DbWeight::get().reads(100)) + .saturating_add(T::DbWeight::get().writes(100)) + } + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestEvictedDate (r:1 w:1) + /// Proof: Anchor LatestEvictedDate (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Anchor EvictedAnchorRoots (r:100 w:100) + /// Proof: Anchor EvictedAnchorRoots (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72010000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72020000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72030000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72040000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72050000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72060000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72070000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72080000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72090000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f720f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72100000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72110000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72120000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72130000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72140000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72150000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72160000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72170000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72180000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72190000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f721f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72200000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72210000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72220000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72230000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72240000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72250000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72260000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72270000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72280000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72290000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f722f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72300000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72310000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72320000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72330000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72340000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72350000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72360000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72370000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72380000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72390000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f723f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72400000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72410000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72420000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72430000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72440000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72450000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72460000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72470000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72480000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72490000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f724f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72500000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72510000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72520000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72530000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72540000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72550000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72560000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72570000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72580000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72590000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725a0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725b0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725c0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725d0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725e0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f725f0000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72600000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72610000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72620000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72630000` (r:1 w:0) + /// Storage: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Proof Skipped: unknown `0x3a6368696c645f73746f726167653a64656661756c743a616e63686f72640000` (r:1 w:0) + /// Storage: Anchor LatestEvictedAnchorIndex (r:1 w:1) + /// Proof: Anchor LatestEvictedAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor LatestAnchorIndex (r:1 w:0) + /// Proof: Anchor LatestAnchorIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Anchor AnchorIndexes (r:100 w:100) + /// Proof: Anchor AnchorIndexes (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Anchor AnchorEvictDates (r:100 w:100) + /// Proof: Anchor AnchorEvictDates (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Proof Skipped: unknown `0x01d5998dcaa249dfa2a455ae4c045d761623f268227068931dbabca3732aa41f` (r:0 w:1) + /// Storage: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Proof Skipped: unknown `0x04575ee0699f1fa86cccfdcf4285aa81b9bfa0f8837cf533346d722970f1a704` (r:0 w:1) + /// Storage: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Proof Skipped: unknown `0x0959721f200e92d5090cee3c2c4546c11f9bfd16ded1e70e6781d2402880f1f3` (r:0 w:1) + /// Storage: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Proof Skipped: unknown `0x0a958b15afac1ffb0c6e73c553bd8b4ba94ad2d0cc118dcd2a7bc8802e2e772a` (r:0 w:1) + /// Storage: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Proof Skipped: unknown `0x0c4c531cd9dcf8573a6350d0ac9fb060d273156bdee4fdae0043b6fee5bda27c` (r:0 w:1) + /// Storage: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Proof Skipped: unknown `0x0cd3f3ee9420f9c3b2e70862996e8d02e87d1f148632a36b8f72c9548b10b856` (r:0 w:1) + /// Storage: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Proof Skipped: unknown `0x10876da12e1227a2c04872ce311f768aaf3e21458e6ad1c04f044c97fe8e214e` (r:0 w:1) + /// Storage: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Proof Skipped: unknown `0x10b360a66313de6ab2d43019c5fd7ea0db088efb3e1d4a24d89775e66e089cff` (r:0 w:1) + /// Storage: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Proof Skipped: unknown `0x16d33ce142442dfbe857e2c9e0648d026c6bb367d467d6922c2c1133aaa3d7b8` (r:0 w:1) + /// Storage: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Proof Skipped: unknown `0x16e133fb9e42d5a2a9a2e21b2e0efd735fccb527162a21cf520c3aecd84c89ed` (r:0 w:1) + /// Storage: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Proof Skipped: unknown `0x16fcb5e799a48fa04deaaaa71c85bc8e9126bd4b5dbcb3a1f8068ab14bc1c26f` (r:0 w:1) + /// Storage: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Proof Skipped: unknown `0x1b3289127bc95ed117e77d479ccd3ac4477ef8d32df7265bbd42c75bf1945464` (r:0 w:1) + /// Storage: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Proof Skipped: unknown `0x1ecb14235f21b57f49e32ac4f35a1af6a71f96867f0bc61bc5905b8d437b6bde` (r:0 w:1) + /// Storage: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Proof Skipped: unknown `0x1f8b0dafc67f9d378cf0596c5d49f220e5880b9c74ccaadac2206a35ec92715a` (r:0 w:1) + /// Storage: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Proof Skipped: unknown `0x24a8d9c362d9365f46f899adb37f6b61134dceaa80f96a9cda6b059a1301f380` (r:0 w:1) + /// Storage: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Proof Skipped: unknown `0x2a00fca93dceceb635a80a95e8f785b189a4ce35f90a17acba5d1bcacf895a84` (r:0 w:1) + /// Storage: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Proof Skipped: unknown `0x2b318def38ef5f2f8db787e365834ece79fbde70c22cf7bd6c9326995fd4c07f` (r:0 w:1) + /// Storage: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Proof Skipped: unknown `0x2fbeff7b90831a847716e729a30f028899726193b4406a1c91fce4e97beb61b5` (r:0 w:1) + /// Storage: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Proof Skipped: unknown `0x30dc983a9ad263028d0e91a8a0cf703a2a7fd3834b1102f1ff3f8c8876a207bf` (r:0 w:1) + /// Storage: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Proof Skipped: unknown `0x3187d0cdac28db7ec343a07f0b2e44fc56986f0a9c2062d5fa60f99419707bea` (r:0 w:1) + /// Storage: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Proof Skipped: unknown `0x3596cd6b45e209629c71765c804f324ed440f7a1cb2ff6cb542156fd5d213de2` (r:0 w:1) + /// Storage: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Proof Skipped: unknown `0x3645890bd8ab0cc13921468d56eee7da40fbe28dc05bc30a64f05a2c03a1912e` (r:0 w:1) + /// Storage: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Proof Skipped: unknown `0x384b604969634cf37d988e886b5267a51baeb797e09a1d1a0893e5be8fc553df` (r:0 w:1) + /// Storage: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Proof Skipped: unknown `0x3c056a888ea28c9294c91723916f5891141a824048335e32532e6605ce0457e0` (r:0 w:1) + /// Storage: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Proof Skipped: unknown `0x3c5fd1d5c95885c6b44e0f3995886046d906821de1ed5ee95b51b17c42d3295b` (r:0 w:1) + /// Storage: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Proof Skipped: unknown `0x3e74dfe3befcf6fa20eb902c2007ba7fd831619013aa99e016284597b896115b` (r:0 w:1) + /// Storage: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Proof Skipped: unknown `0x42f1cff854d41b18ae379b012a1e712f036bcd839244d5c6324f12c28f6fd6e9` (r:0 w:1) + /// Storage: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Proof Skipped: unknown `0x457803d743c32f50866dbf7aabb339a1d8b6b759783b0627128f0cfd3d6c8775` (r:0 w:1) + /// Storage: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Proof Skipped: unknown `0x4cb17fd2f1d1b2eff69f0ffa1a97ff13e7bf4f05a7a99dd06e503e7546b23906` (r:0 w:1) + /// Storage: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Proof Skipped: unknown `0x58357c4f5a9881658ffc42faa5f48e2810169bf85c8c78011696a17b59728ef5` (r:0 w:1) + /// Storage: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Proof Skipped: unknown `0x5baa983aa91ad92c66e17d16e0757ec4a67ec2ce5b95f4d02ec22fba0e485da0` (r:0 w:1) + /// Storage: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Proof Skipped: unknown `0x5da83d0712f41714545470b781e0a43c65a0ac977327475baa98b5cd94938f17` (r:0 w:1) + /// Storage: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Proof Skipped: unknown `0x6365aeecd6b54d3166f3df46d8c7b404711ca54b4284e8faf67eb014fa3685f8` (r:0 w:1) + /// Storage: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Proof Skipped: unknown `0x683b74d821a8019cbfc9dbe47b50b0f377e0eef16dbc52f7f931ae713fd3f644` (r:0 w:1) + /// Storage: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Proof Skipped: unknown `0x6b02568ad8557dc3d66463abfd1d7f298a0b314fe4bf7d5be79b66768096ed90` (r:0 w:1) + /// Storage: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Proof Skipped: unknown `0x6b05c068aecc171915a61cf59146e7f9a69b9bba39f4df50cecfeb454850b4c9` (r:0 w:1) + /// Storage: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Proof Skipped: unknown `0x6b5529ac614dcbd6113176256a4f5809eb667bddab2e22579306de0a1f83f287` (r:0 w:1) + /// Storage: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Proof Skipped: unknown `0x6cd1381490331969f37f1e6575081f42f1bd8ae0cc79d70fc52ed178b5d75bd0` (r:0 w:1) + /// Storage: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Proof Skipped: unknown `0x6f5b021a9f57d7669ed7269e7d8785acf255f15785bf452a03a4decc184fd403` (r:0 w:1) + /// Storage: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Proof Skipped: unknown `0x764bac7888f79c071087d351a356a09cb2490cb6ea6d71f0cd391de89a885cd2` (r:0 w:1) + /// Storage: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Proof Skipped: unknown `0x7aedb653a5de5739b9d3594196693fd51653fcd59b442e0eb9f64265db188044` (r:0 w:1) + /// Storage: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Proof Skipped: unknown `0x7ca04bdeb932896fd908eb86d4136e9e2462575ebdf981001c1cd3ca6a2faaec` (r:0 w:1) + /// Storage: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Proof Skipped: unknown `0x7ceee738f5af899bd2f967a928019e4a0ecb8715509668dcc039badfe148b45e` (r:0 w:1) + /// Storage: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Proof Skipped: unknown `0x7e700ce9c411e35485babec60c2b68f40c512bc8399c5cee0c1e4264e63f36d1` (r:0 w:1) + /// Storage: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Proof Skipped: unknown `0x80c020f2e70a170ee2f34af3daeda4c2097d14a35f5b1f2d23c2287e5e930f55` (r:0 w:1) + /// Storage: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8101d04cf92ee55f6c2a798c7b16da4cc8c511fd822b13093d0f53f5523718d0` (r:0 w:1) + /// Storage: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Proof Skipped: unknown `0x85172de32d6b5871235d50648541b1bd007807512231f9b81f25cb5e20141820` (r:0 w:1) + /// Storage: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Proof Skipped: unknown `0x85e9ccd05d28607dcce0dc5be4f34a7d56d3b83b6c63162b2787fc0e6decf2a7` (r:0 w:1) + /// Storage: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Proof Skipped: unknown `0x87b3d065618080e576b534cf68b60d09c4cca0b71a8b6321337cc23be47e7329` (r:0 w:1) + /// Storage: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Proof Skipped: unknown `0x892ec564231143cc6294a8750b924df2207d91ea3508501d2bd84bee7947b9d0` (r:0 w:1) + /// Storage: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Proof Skipped: unknown `0x8980988eacf42b40c4fc8aa995ae2e059a66c6935626c3e30f1d6842335368d0` (r:0 w:1) + /// Storage: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Proof Skipped: unknown `0x8db2380506697daa88c7a72906d747535ffb12c0ca2a4a6443074bb0fdd8f256` (r:0 w:1) + /// Storage: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Proof Skipped: unknown `0x8e098b9b896a97df275aba887f591c3076220e02adf682c98808e4ba53e6a773` (r:0 w:1) + /// Storage: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Proof Skipped: unknown `0x8e590007efc113bc10a61c478d26803cdae5572d4c70547b3c9813b3ce396826` (r:0 w:1) + /// Storage: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Proof Skipped: unknown `0x96e31df89b1f00b96c993bd9de31e32e7e59c0a185cd0b31adc4e969746c8ea6` (r:0 w:1) + /// Storage: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Proof Skipped: unknown `0x9ae7305289647b636a8702b2316e5482f1a807fa398687068fb653527368f9bc` (r:0 w:1) + /// Storage: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Proof Skipped: unknown `0x9b9660b6fc1992a09573eaa9110c4a08d40c1f439304a47b9776645bc278fc75` (r:0 w:1) + /// Storage: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Proof Skipped: unknown `0xa04f2ef3bb509dfec9d7a97c4778ab2e477af9c5cbda3a1c6e57514314a3f9a5` (r:0 w:1) + /// Storage: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Proof Skipped: unknown `0xa16d64c1e08b47144c2c8e37872486cf440dda823e2ea05f480fedfe83060f17` (r:0 w:1) + /// Storage: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Proof Skipped: unknown `0xa4ad0a32c2781a59ea8a6d58e26fa7dc0b2a08f8c4c938661f5f3ccd8f8eb8ce` (r:0 w:1) + /// Storage: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Proof Skipped: unknown `0xab9797fb6926376ee3b6be73e5501e0a3af18d0bc6dfca0d3b5f498602016956` (r:0 w:1) + /// Storage: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Proof Skipped: unknown `0xac4d9f6628449fe129d24b384441fdb445962d2d6bca7603fea0c20f3d04351c` (r:0 w:1) + /// Storage: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Proof Skipped: unknown `0xafecb421bedaa0f8bd89ef18897b77ce61738af42f8a66e3257a079a3d04bef1` (r:0 w:1) + /// Storage: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Proof Skipped: unknown `0xb292dc48cc1057cce335f1d84f295271a2b16aee7018f1bd444febd77f7e5cbb` (r:0 w:1) + /// Storage: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Proof Skipped: unknown `0xb48b9d9955158dbd87abb433511a5968c21cf78f8085088407e24d6ee26f7f56` (r:0 w:1) + /// Storage: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Proof Skipped: unknown `0xb5a7df612d6fb3bc16c1716414897ba5928835d883003371f02106d5a92abd78` (r:0 w:1) + /// Storage: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Proof Skipped: unknown `0xb684abf2ee5018a16a8dbef6633bcb94a07a2cdf4a173e4fec130da86e8ab987` (r:0 w:1) + /// Storage: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Proof Skipped: unknown `0xb86c8391d2a3eb28b9e3b603cf6929849d50e439e0bbc79781b2555f9cbaa013` (r:0 w:1) + /// Storage: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Proof Skipped: unknown `0xba070ba6cf5f2489f98b6841d238eee4fc403d3065b57f9e3e38ca540971024d` (r:0 w:1) + /// Storage: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Proof Skipped: unknown `0xbcb96e5fc092d3ac258a81b5390671817730859598470874ef02f998518bbf58` (r:0 w:1) + /// Storage: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Proof Skipped: unknown `0xc008db6f6d721d80fab2eab8b6dda4f19bd5def30aa7db86dadd6eb799c2f5ad` (r:0 w:1) + /// Storage: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Proof Skipped: unknown `0xc054c4045e44e28cef1884c0aa86d0049b76eaff493a6d694394df7b0cee8136` (r:0 w:1) + /// Storage: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Proof Skipped: unknown `0xc315216d50f4dd95914d6d102976dc09ec4474da5c314a15f09972ded6e71ddb` (r:0 w:1) + /// Storage: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Proof Skipped: unknown `0xc4a2c3fa3cc7ed1611651510eb6e225abab30676f0fad28c115482c7dd61f8e0` (r:0 w:1) + /// Storage: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Proof Skipped: unknown `0xc6cc01d59d3c86a1c12a167e149d784295fcd13862e4afb0a39a8459e6e25561` (r:0 w:1) + /// Storage: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Proof Skipped: unknown `0xc712d8fa08dd521e5f901ca6d36134807c5ec0510e3b52e8ae5a15f7c13d2ebd` (r:0 w:1) + /// Storage: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Proof Skipped: unknown `0xc7e2bc91ff1b307f6995683b76f1904ccdada3cf8f00528c08d4f65911c4888a` (r:0 w:1) + /// Storage: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Proof Skipped: unknown `0xccbca45304d59a1167eaf9b459e09cffce3d90c087ee9edf8e7e2dc40349373b` (r:0 w:1) + /// Storage: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Proof Skipped: unknown `0xccc17a821dda11e5239ea8dbedee5bd6622fc8dd63ee229fc3bd2dead22e8ae2` (r:0 w:1) + /// Storage: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Proof Skipped: unknown `0xccee04c4c0534d4245892ed24d7814cd14a41aeed7e94591354315f5b74d89f5` (r:0 w:1) + /// Storage: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Proof Skipped: unknown `0xcf67e9890d936f6bd205710c9a5cedc653d88fba3c74b7a2b9fe8ce7fce0bd0c` (r:0 w:1) + /// Storage: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Proof Skipped: unknown `0xcfdb7c67ada01beee8308b04c3f32e4c078603d0c84c0e28e605a8ea56dcc362` (r:0 w:1) + /// Storage: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Proof Skipped: unknown `0xd0d54b0c405fea6ff90809070bfd270c88e9a26ad83138eeb077d8f9602670bc` (r:0 w:1) + /// Storage: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Proof Skipped: unknown `0xd1d4eefa482f2ece90773426cd76c1da272ef0e72c1172a4a71b84c1f5f6c7c7` (r:0 w:1) + /// Storage: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Proof Skipped: unknown `0xd282fcd4ae056e61acbc8950a306910569f227182c41e5b88159aed160ba2a58` (r:0 w:1) + /// Storage: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Proof Skipped: unknown `0xd37f5ea81d5d617ed7490c928e4f3a1eba6f234787ba84f31e204e8733cd039f` (r:0 w:1) + /// Storage: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Proof Skipped: unknown `0xd6780cc86f71e3b9d0f0f6977d180e26166b517ee3ee227701f9f36cccae3171` (r:0 w:1) + /// Storage: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Proof Skipped: unknown `0xd79237f18c61e22111652b0e9b809fbe8ca41552b3a927877a294a732b338f63` (r:0 w:1) + /// Storage: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Proof Skipped: unknown `0xd8825b3a03921d36a1543c344d9b3cacce95765f29c735cf3ed72dc9c37ff81b` (r:0 w:1) + /// Storage: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Proof Skipped: unknown `0xdd012b8629cc16d3ad36b73df7dd7d38e8c11ac479b99dedffb10b5007c8049a` (r:0 w:1) + /// Storage: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Proof Skipped: unknown `0xdec56d85d6fffd793180a2ce033397f67fb3b9b7ac3e2b0ef6be2f15e7de435f` (r:0 w:1) + /// Storage: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Proof Skipped: unknown `0xe1f270fea944a3a9db5550d742e3acb3dd449cafb73dce65c1705d0752c1343b` (r:0 w:1) + /// Storage: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Proof Skipped: unknown `0xe4002351550f1b106219729b86aa4776fb907737c9cd7e957c5ce80062a8ff8a` (r:0 w:1) + /// Storage: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Proof Skipped: unknown `0xe45f26671be0fb4144ed09c40b9493c4584affb2c1d1fe6cb067aa2df802027e` (r:0 w:1) + /// Storage: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Proof Skipped: unknown `0xe6b4a4991b976360dacf2c942d16326dd53584aca6ed1ae4e78f668d7b1163c1` (r:0 w:1) + /// Storage: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Proof Skipped: unknown `0xe8150db238f56576dcf5e1b98f3915361092aa174b16e6cda3e78c28b6444dc8` (r:0 w:1) + /// Storage: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Proof Skipped: unknown `0xebc5f1d9670cdeb0655d79e95c9602ec1d85ad989ce78194dfd1a31e9fb4994c` (r:0 w:1) + /// Storage: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Proof Skipped: unknown `0xed0df01311d268fc75f0da4859b6508e1c445e713847efbc18528d731316cf48` (r:0 w:1) + /// Storage: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Proof Skipped: unknown `0xee60c64e1e32117f948ee71d391f978e8ac98c2bd869322fc25164502e3f7a9b` (r:0 w:1) + /// Storage: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) + /// Proof Skipped: unknown `0xf7e4b8a5415405a940e730546df85583c8c23956d99a3be18e09eebf3639d312` (r:0 w:1) + fn evict_anchors() -> Weight { + // Proof Size summary in bytes: + // Measured: `18358` + // Estimated: `4680108` + // Minimum execution time: 1_875_548 nanoseconds. + Weight::from_parts(1_894_002_000, 4680108) + .saturating_add(T::DbWeight::get().reads(404)) + .saturating_add(T::DbWeight::get().writes(402)) + } +} diff --git a/runtime/development/src/weights/pallet_balances.rs b/runtime/development/src/weights/pallet_balances.rs index 90307b44ef..446933fb3c 100644 --- a/runtime/development/src/weights/pallet_balances.rs +++ b/runtime/development/src/weights/pallet_balances.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_balances + +//! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_balances @@ -16,61 +19,93 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_balances.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_balances.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_balances using the Substrate node and recommended -/// hardware. +/// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - Weight::from_ref_time(86_575_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1829` + // Estimated: `2603` + // Minimum execution time: 73_337 nanoseconds. + Weight::from_parts(74_117_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(65_312_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1538` + // Estimated: `2603` + // Minimum execution time: 52_207 nanoseconds. + Weight::from_parts(53_409_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { - Weight::from_ref_time(40_240_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `2603` + // Minimum execution time: 39_463 nanoseconds. + Weight::from_parts(40_666_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { - Weight::from_ref_time(47_531_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `2603` + // Minimum execution time: 45_765 nanoseconds. + Weight::from_parts(46_747_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - Weight::from_ref_time(86_506_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `1829` + // Estimated: `5206` + // Minimum execution time: 73_607 nanoseconds. + Weight::from_parts(74_519_000, 5206) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } - + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { - Weight::from_ref_time(77_186_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1538` + // Estimated: `2603` + // Minimum execution time: 61_054 nanoseconds. + Weight::from_parts(62_206_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { - Weight::from_ref_time(36_130_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `1572` + // Estimated: `2603` + // Minimum execution time: 33_031 nanoseconds. + Weight::from_parts(34_183_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_block_rewards.rs b/runtime/development/src/weights/pallet_block_rewards.rs index 887fb1c561..735dd95ea1 100644 --- a/runtime/development/src/weights/pallet_block_rewards.rs +++ b/runtime/development/src/weights/pallet_block_rewards.rs @@ -2,15 +2,16 @@ //! Autogenerated weights for `pallet_block_rewards` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Williams-Laptop.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_block_rewards @@ -18,7 +19,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_block_rewards.rs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_block_rewards.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -29,30 +30,48 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_block_rewards`. pub struct WeightInfo(PhantomData); -impl pallet_block_rewards::weights::WeightInfo for WeightInfo { - // Storage: BlockRewardsBase Currencies (r:1 w:0) - // Storage: BlockRewardsBase Groups (r:1 w:0) - // Storage: BlockRewardsBase StakeAccounts (r:1 w:1) - // Storage: System Account (r:2 w:2) +impl pallet_block_rewards::WeightInfo for WeightInfo { + /// Storage: BlockRewardsBase Currency (r:1 w:0) + /// Proof: BlockRewardsBase Currency (max_values: None, max_size: Some(79), added: 2554, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase Group (r:1 w:0) + /// Proof: BlockRewardsBase Group (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: BlockRewardsBase StakeAccount (r:1 w:1) + /// Proof: BlockRewardsBase StakeAccount (max_values: None, max_size: Some(123), added: 2598, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_reward() -> Weight { - // Minimum execution time: 46_000 nanoseconds. - Weight::from_ref_time(48_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `678` + // Estimated: `12885` + // Minimum execution time: 58_770 nanoseconds. + Weight::from_parts(60_482_000, 12885) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_collator_reward() -> Weight { - // Minimum execution time: 7_000 nanoseconds. - Weight::from_ref_time(7_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `138` + // Estimated: `3115` + // Minimum execution time: 12_142 nanoseconds. + Weight::from_parts(12_674_000, 3115) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: BlockRewards NextSessionChanges (r:1 w:1) - // Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Storage: BlockRewards NextSessionChanges (r:1 w:1) + /// Proof: BlockRewards NextSessionChanges (max_values: Some(1), max_size: Some(2089), added: 2584, mode: MaxEncodedLen) + /// Storage: BlockRewards ActiveSessionData (r:1 w:0) + /// Proof: BlockRewards ActiveSessionData (max_values: Some(1), max_size: Some(36), added: 531, mode: MaxEncodedLen) fn set_total_reward() -> Weight { - // Minimum execution time: 9_000 nanoseconds. - Weight::from_ref_time(9_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `97` + // Estimated: `3115` + // Minimum execution time: 11_201 nanoseconds. + Weight::from_parts(11_511_000, 3115) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_collator_allowlist.rs b/runtime/development/src/weights/pallet_collator_allowlist.rs index 752a2e9eec..4fd399153f 100644 --- a/runtime/development/src/weights/pallet_collator_allowlist.rs +++ b/runtime/development/src/weights/pallet_collator_allowlist.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_collator_allowlist + +//! Autogenerated weights for `pallet_collator_allowlist` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_collator_allowlist @@ -16,31 +19,40 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_collator_allowlist.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_collator_allowlist.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_collator_allowlist using the Substrate node and -/// recommended hardware. +/// Weight functions for `pallet_collator_allowlist`. pub struct WeightInfo(PhantomData); -impl pallet_collator_allowlist::weights::WeightInfo for WeightInfo { +impl pallet_collator_allowlist::WeightInfo for WeightInfo { + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn add() -> Weight { - Weight::from_ref_time(33_331_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `490` + // Estimated: `5472` + // Minimum execution time: 25_557 nanoseconds. + Weight::from_parts(26_329_000, 5472) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CollatorAllowlist Allowlist (r:1 w:1) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) fn remove() -> Weight { - Weight::from_ref_time(27_090_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `166` + // Estimated: `2507` + // Minimum execution time: 18_975 nanoseconds. + Weight::from_parts(19_687_000, 2507) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_collator_selection.rs b/runtime/development/src/weights/pallet_collator_selection.rs index 678de3e710..30988e15a2 100644 --- a/runtime/development/src/weights/pallet_collator_selection.rs +++ b/runtime/development/src/weights/pallet_collator_selection.rs @@ -2,15 +2,16 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Williams-Laptop.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_collator_selection @@ -18,7 +19,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_collator_selection.rs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_collator_selection.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -30,79 +31,133 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_collator_selection`. pub struct WeightInfo(PhantomData); impl pallet_collator_selection::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Storage: CollatorAllowlist Allowlist (r:100 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:100 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection Invulnerables (r:0 w:1) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// The range of component `b` is `[1, 100]`. /// The range of component `b` is `[1, 100]`. fn set_invulnerables(b: u32, ) -> Weight { - // Minimum execution time: 18_000 nanoseconds. - Weight::from_ref_time(13_766_079 as u64) - // Standard Error: 18_962 - .saturating_add(Weight::from_ref_time(2_866_571 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `400 + b * (144 ±0)` + // Estimated: `397 + b * (5127 ±0)` + // Minimum execution time: 25_277 nanoseconds. + Weight::from_parts(23_693_174, 397) + // Standard Error: 4_832 + .saturating_add(Weight::from_ref_time(5_694_808).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(5127).saturating_mul(b.into())) } - // Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Storage: CollatorSelection DesiredCandidates (r:0 w:1) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_desired_candidates() -> Weight { - // Minimum execution time: 11_000 nanoseconds. - Weight::from_ref_time(12_000_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 14_998 nanoseconds. + Weight::from_ref_time(15_889_000) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Storage: CollatorSelection CandidacyBond (r:0 w:1) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_candidacy_bond() -> Weight { - // Minimum execution time: 11_000 nanoseconds. - Weight::from_ref_time(12_000_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_639 nanoseconds. + Weight::from_ref_time(11_251_000) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection DesiredCandidates (r:1 w:0) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: Session NextKeys (r:1 w:0) - // Storage: CollatorSelection CandidacyBond (r:1 w:0) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) - /// The range of component `c` is `[1, 999]`. + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection DesiredCandidates (r:1 w:0) + /// Proof: CollatorSelection DesiredCandidates (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: CollatorAllowlist Allowlist (r:1 w:0) + /// Proof: CollatorAllowlist Allowlist (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:0) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: CollatorSelection CandidacyBond (r:1 w:0) + /// Proof: CollatorSelection CandidacyBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// The range of component `c` is `[1, 99]`. + /// The range of component `c` is `[1, 99]`. fn register_as_candidate(c: u32, ) -> Weight { - // Minimum execution time: 41_000 nanoseconds. - Weight::from_ref_time(42_888_647 as u64) - // Standard Error: 1_823 - .saturating_add(Weight::from_ref_time(120_814 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `1187 + c * (52 ±0)` + // Estimated: `16122 + c * (53 ±0)` + // Minimum execution time: 59_931 nanoseconds. + Weight::from_parts(62_764_209, 16122) + // Standard Error: 665 + .saturating_add(Weight::from_ref_time(124_788).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(53).saturating_mul(c.into())) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) - /// The range of component `c` is `[6, 1000]`. + /// Storage: CollatorSelection Candidates (r:1 w:1) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// The range of component `c` is `[6, 100]`. + /// The range of component `c` is `[6, 100]`. fn leave_intent(c: u32, ) -> Weight { - // Minimum execution time: 31_000 nanoseconds. - Weight::from_ref_time(24_963_536 as u64) - // Standard Error: 1_964 - .saturating_add(Weight::from_ref_time(118_803 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `430 + c * (49 ±0)` + // Estimated: `5297` + // Minimum execution time: 37_239 nanoseconds. + Weight::from_parts(39_032_360, 5297) + // Standard Error: 1_038 + .saturating_add(Weight::from_ref_time(130_212).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: System Account (r:2 w:2) - // Storage: System BlockWeight (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:0 w:1) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { - // Minimum execution time: 34_000 nanoseconds. - Weight::from_ref_time(38_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `5749` + // Minimum execution time: 42_960 nanoseconds. + Weight::from_parts(44_002_000, 5749) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) } - // Storage: CollatorSelection Candidates (r:1 w:1) - // Storage: CollatorSelection LastAuthoredBlock (r:1000 w:1) - // Storage: System Account (r:1 w:1) - // Storage: CollatorSelection Invulnerables (r:1 w:0) - // Storage: System BlockWeight (r:1 w:1) - /// The range of component `r` is `[1, 1000]`. - /// The range of component `c` is `[1, 1000]`. - fn new_session(_r: u32, c: u32, ) -> Weight { - // Minimum execution time: 15_000 nanoseconds. - Weight::from_ref_time(16_000_000 as u64) - // Standard Error: 632_608 - .saturating_add(Weight::from_ref_time(22_335_806 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(c as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(c as u64))) + /// Storage: CollatorSelection Candidates (r:1 w:0) + /// Proof: CollatorSelection Candidates (max_values: Some(1), max_size: Some(4802), added: 5297, mode: MaxEncodedLen) + /// Storage: CollatorSelection LastAuthoredBlock (r:100 w:0) + /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: CollatorSelection Invulnerables (r:1 w:0) + /// Proof: CollatorSelection Invulnerables (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System BlockWeight (r:1 w:1) + /// Proof: System BlockWeight (max_values: Some(1), max_size: Some(48), added: 543, mode: MaxEncodedLen) + /// Storage: System Account (r:95 w:95) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 100]`. + /// The range of component `c` is `[1, 100]`. + /// The range of component `r` is `[1, 100]`. + /// The range of component `c` is `[1, 100]`. + fn new_session(r: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2629 + r * (147 ±0) + c * (97 ±0)` + // Estimated: `909314980955027 + r * (2597 ±4) + c * (2519 ±0)` + // Minimum execution time: 25_317 nanoseconds. + Weight::from_parts(25_678_000, 909314980955027) + // Standard Error: 208_679 + .saturating_add(Weight::from_ref_time(15_673_406).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(2519).saturating_mul(c.into())) } } diff --git a/runtime/development/src/weights/pallet_collective.rs b/runtime/development/src/weights/pallet_collective.rs new file mode 100644 index 0000000000..bbbe6f0490 --- /dev/null +++ b/runtime/development/src/weights/pallet_collective.rs @@ -0,0 +1,274 @@ + +//! Autogenerated weights for `pallet_collective` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_collective +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_collective.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_collective`. +pub struct WeightInfo(PhantomData); +impl pallet_collective::WeightInfo for WeightInfo { + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `m` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `p` is `[0, 100]`. + fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` + // Estimated: `16190 + m * (7809 ±23) + p * (10238 ±23)` + // Minimum execution time: 22_181 nanoseconds. + Weight::from_parts(22_382_000, 16190) + // Standard Error: 64_236 + .saturating_add(Weight::from_ref_time(5_017_878).saturating_mul(m.into())) + // Standard Error: 64_236 + .saturating_add(Weight::from_ref_time(8_816_080).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) + } + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `631 + m * (32 ±0)` + // Minimum execution time: 22_962 nanoseconds. + Weight::from_parts(26_779_786, 631) + // Standard Error: 430 + .saturating_add(Weight::from_ref_time(1_344).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) + } + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn propose_execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `135 + m * (32 ±0)` + // Estimated: `3242 + m * (64 ±0)` + // Minimum execution time: 27_642 nanoseconds. + Weight::from_parts(26_433_668, 3242) + // Standard Error: 121 + .saturating_add(Weight::from_ref_time(1_876).saturating_mul(b.into())) + // Standard Error: 1_251 + .saturating_add(Weight::from_ref_time(34_391).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + } + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `457 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `5860 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 34_604 nanoseconds. + Weight::from_parts(34_796_534, 5860) + // Standard Error: 105 + .saturating_add(Weight::from_ref_time(2_792).saturating_mul(b.into())) + // Standard Error: 1_104 + .saturating_add(Weight::from_ref_time(30_927).saturating_mul(m.into())) + // Standard Error: 1_090 + .saturating_add(Weight::from_ref_time(196_263).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + } + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `907 + m * (64 ±0)` + // Estimated: `4782 + m * (128 ±0)` + // Minimum execution time: 30_346 nanoseconds. + Weight::from_parts(31_236_497, 4782) + // Standard Error: 831 + .saturating_add(Weight::from_ref_time(48_491).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) + } + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `527 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `5497 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 38_802 nanoseconds. + Weight::from_parts(39_018_269, 5497) + // Standard Error: 1_122 + .saturating_add(Weight::from_ref_time(34_336).saturating_mul(m.into())) + // Standard Error: 1_094 + .saturating_add(Weight::from_ref_time(178_059).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + } + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `863 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `8768 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 55_484 nanoseconds. + Weight::from_parts(56_878_974, 8768) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(3_290).saturating_mul(b.into())) + // Standard Error: 3_027 + .saturating_add(Weight::from_ref_time(8_523).saturating_mul(m.into())) + // Standard Error: 2_950 + .saturating_add(Weight::from_ref_time(227_600).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) + } + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `547 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `6600 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 41_838 nanoseconds. + Weight::from_parts(41_889_250, 6600) + // Standard Error: 1_132 + .saturating_add(Weight::from_ref_time(40_912).saturating_mul(m.into())) + // Standard Error: 1_104 + .saturating_add(Weight::from_ref_time(183_713).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + } + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `10070 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 59_231 nanoseconds. + Weight::from_parts(60_514_207, 10070) + // Standard Error: 166 + .saturating_add(Weight::from_ref_time(2_880).saturating_mul(b.into())) + // Standard Error: 1_764 + .saturating_add(Weight::from_ref_time(33_489).saturating_mul(m.into())) + // Standard Error: 1_719 + .saturating_add(Weight::from_ref_time(221_396).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) + } + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `p` is `[1, 100]`. + fn disapprove_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `292 + p * (32 ±0)` + // Estimated: `1371 + p * (96 ±0)` + // Minimum execution time: 22_161 nanoseconds. + Weight::from_parts(23_967_563, 1371) + // Standard Error: 867 + .saturating_add(Weight::from_ref_time(171_643).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) + } +} diff --git a/runtime/development/src/weights/pallet_crowdloan_claim.rs b/runtime/development/src/weights/pallet_crowdloan_claim.rs index ef9bce6d45..00b4fc15bc 100644 --- a/runtime/development/src/weights/pallet_crowdloan_claim.rs +++ b/runtime/development/src/weights/pallet_crowdloan_claim.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_crowdloan_claim + +//! Autogenerated weights for `pallet_crowdloan_claim` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_crowdloan_claim @@ -16,63 +19,182 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_crowdloan_claim.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_crowdloan_claim.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_crowdloan_claim using the Substrate node and recommended -/// hardware. +/// Weight functions for `pallet_crowdloan_claim`. pub struct WeightInfo(PhantomData); -impl pallet_crowdloan_claim::weights::WeightInfo for WeightInfo { +impl pallet_crowdloan_claim::WeightInfo for WeightInfo { + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ed25519() -> Weight { - Weight::from_ref_time(299_358_000) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `17661` + // Minimum execution time: 210_352 nanoseconds. + Weight::from_parts(213_026_000, 17661) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(5)) } - + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_sr25519() -> Weight { - Weight::from_ref_time(307_081_000) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Proof Size summary in bytes: + // Measured: `658` + // Estimated: `17661` + // Minimum execution time: 213_567 nanoseconds. + Weight::from_parts(215_962_000, 17661) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(5)) } - + /// Storage: CrowdloanClaim CurrIndex (r:1 w:0) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:0) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:0) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim ProcessedClaims (r:1 w:1) + /// Proof: CrowdloanClaim ProcessedClaims (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:1 w:0) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingStart (r:1 w:0) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:1 w:0) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:1 w:0) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn claim_reward_ecdsa() -> Weight { - Weight::from_ref_time(481_336_000) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Proof Size summary in bytes: + // Measured: `619` + // Estimated: `17661` + // Minimum execution time: 194_302 nanoseconds. + Weight::from_parts(196_496_000, 17661) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(5)) } - + /// Storage: CrowdloanClaim CurrIndex (r:1 w:1) + /// Proof: CrowdloanClaim CurrIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeaseStart (r:1 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LeasePeriod (r:1 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim PrevIndex (r:1 w:0) + /// Proof: CrowdloanClaim PrevIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - Weight::from_ref_time(40_071_000) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1996` + // Minimum execution time: 24_125 nanoseconds. + Weight::from_parts(24_927_000, 1996) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(6)) } - + /// Storage: CrowdloanClaim LeaseStart (r:0 w:1) + /// Proof: CrowdloanClaim LeaseStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_start() -> Weight { - Weight::from_ref_time(20_773_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_511 nanoseconds. + Weight::from_ref_time(11_992_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanClaim LeasePeriod (r:0 w:1) + /// Proof: CrowdloanClaim LeasePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_lease_period() -> Weight { - Weight::from_ref_time(20_782_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_762 nanoseconds. + Weight::from_ref_time(12_032_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanClaim Contributions (r:0 w:1) + /// Proof: CrowdloanClaim Contributions (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) fn set_contributions_root() -> Weight { - Weight::from_ref_time(22_172_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_453 nanoseconds. + Weight::from_ref_time(12_974_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanClaim LockedAt (r:0 w:1) + /// Proof: CrowdloanClaim LockedAt (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_locked_at() -> Weight { - Weight::from_ref_time(20_800_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_641 nanoseconds. + Weight::from_ref_time(11_982_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanClaim CrowdloanTrieIndex (r:0 w:1) + /// Proof: CrowdloanClaim CrowdloanTrieIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_crowdloan_trie_index() -> Weight { - Weight::from_ref_time(20_887_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_421 nanoseconds. + Weight::from_ref_time(11_832_000) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_crowdloan_reward.rs b/runtime/development/src/weights/pallet_crowdloan_reward.rs index 435d61aac2..0e975097ee 100644 --- a/runtime/development/src/weights/pallet_crowdloan_reward.rs +++ b/runtime/development/src/weights/pallet_crowdloan_reward.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_crowdloan_reward + +//! Autogenerated weights for `pallet_crowdloan_reward` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_crowdloan_reward @@ -16,35 +19,60 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_crowdloan_reward.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_crowdloan_reward.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_crowdloan_reward using the Substrate node and recommended -/// hardware. +/// Weight functions for `pallet_crowdloan_reward`. pub struct WeightInfo(PhantomData); -impl pallet_crowdloan_reward::weights::WeightInfo for WeightInfo { +impl pallet_crowdloan_reward::WeightInfo for WeightInfo { + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn initialize() -> Weight { - Weight::from_ref_time(23_354_000).saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_365 nanoseconds. + Weight::from_ref_time(14_106_000) + .saturating_add(T::DbWeight::get().writes(3)) } - + /// Storage: CrowdloanReward VestingStart (r:0 w:1) + /// Proof: CrowdloanReward VestingStart (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_start() -> Weight { - Weight::from_ref_time(20_702_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_331 nanoseconds. + Weight::from_ref_time(11_852_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanReward VestingPeriod (r:0 w:1) + /// Proof: CrowdloanReward VestingPeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_vesting_period() -> Weight { - Weight::from_ref_time(20_663_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_361 nanoseconds. + Weight::from_ref_time(11_772_000) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: CrowdloanReward DirectPayoutRatio (r:0 w:1) + /// Proof: CrowdloanReward DirectPayoutRatio (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_direct_payout_ratio() -> Weight { - Weight::from_ref_time(20_801_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_681 nanoseconds. + Weight::from_ref_time(11_972_000) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_democracy.rs b/runtime/development/src/weights/pallet_democracy.rs new file mode 100644 index 0000000000..1d2b2cb9e6 --- /dev/null +++ b/runtime/development/src/weights/pallet_democracy.rs @@ -0,0 +1,376 @@ + +//! Autogenerated weights for `pallet_democracy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_democracy +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_democracy.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_democracy`. +pub struct WeightInfo(PhantomData); +impl pallet_democracy::WeightInfo for WeightInfo { + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + fn propose() -> Weight { + // Proof Size summary in bytes: + // Measured: `4864` + // Estimated: `23409` + // Minimum execution time: 50_995 nanoseconds. + Weight::from_parts(52_327_000, 23409) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + fn second() -> Weight { + // Proof Size summary in bytes: + // Measured: `3620` + // Estimated: `5705` + // Minimum execution time: 44_533 nanoseconds. + Weight::from_parts(45_645_000, 5705) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + fn vote_new() -> Weight { + // Proof Size summary in bytes: + // Measured: `3517` + // Estimated: `12720` + // Minimum execution time: 57_527 nanoseconds. + Weight::from_parts(58_709_000, 12720) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + fn vote_existing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3539` + // Estimated: `12720` + // Minimum execution time: 57_396 nanoseconds. + Weight::from_parts(58_359_000, 12720) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + fn emergency_cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `5184` + // Minimum execution time: 26_299 nanoseconds. + Weight::from_parts(26_760_000, 5184) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + fn blacklist() -> Weight { + // Proof Size summary in bytes: + // Measured: `6362` + // Estimated: `31411` + // Minimum execution time: 113_601 nanoseconds. + Weight::from_parts(115_816_000, 31411) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + fn external_propose() -> Weight { + // Proof Size summary in bytes: + // Measured: `3448` + // Estimated: `6340` + // Minimum execution time: 18_725 nanoseconds. + Weight::from_parts(20_679_000, 6340) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + fn external_propose_majority() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_950 nanoseconds. + Weight::from_ref_time(5_360_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + fn external_propose_default() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_109 nanoseconds. + Weight::from_ref_time(5_400_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + fn fast_track() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `1126` + // Minimum execution time: 24_536 nanoseconds. + Weight::from_parts(25_127_000, 1126) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + fn veto_external() -> Weight { + // Proof Size summary in bytes: + // Measured: `3477` + // Estimated: `6340` + // Minimum execution time: 29_765 nanoseconds. + Weight::from_parts(30_476_000, 6340) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn cancel_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `6241` + // Estimated: `28108` + // Minimum execution time: 93_905 nanoseconds. + Weight::from_parts(95_948_000, 28108) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + fn cancel_referendum() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_994 nanoseconds. + Weight::from_ref_time(13_435_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn on_initialize_base(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `998 + r * (2676 ±0)` + // Minimum execution time: 9_849 nanoseconds. + Weight::from_parts(11_673_837, 998) + // Standard Error: 6_204 + .saturating_add(Weight::from_ref_time(3_796_302).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `19318 + r * (2676 ±0)` + // Minimum execution time: 14_327 nanoseconds. + Weight::from_parts(16_751_056, 19318) + // Standard Error: 5_860 + .saturating_add(Weight::from_ref_time(3_786_297).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn delegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `914 + r * (139 ±0)` + // Estimated: `22584 + r * (2676 ±0)` + // Minimum execution time: 48_801 nanoseconds. + Weight::from_parts(53_950_712, 22584) + // Standard Error: 7_320 + .saturating_add(Weight::from_ref_time(4_820_964).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn undelegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `547 + r * (139 ±0)` + // Estimated: `12540 + r * (2676 ±0)` + // Minimum execution time: 28_513 nanoseconds. + Weight::from_parts(28_322_604, 12540) + // Standard Error: 8_047 + .saturating_add(Weight::from_ref_time(4_900_339).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + fn clear_public_proposals() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_019 nanoseconds. + Weight::from_ref_time(5_321_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn unlock_remove(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `12647` + // Minimum execution time: 27_151 nanoseconds. + Weight::from_parts(34_372_218, 12647) + // Standard Error: 1_579 + .saturating_add(Weight::from_ref_time(28_501).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `r` is `[0, 99]`. + fn unlock_set(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `580 + r * (22 ±0)` + // Estimated: `12647` + // Minimum execution time: 32_050 nanoseconds. + Weight::from_parts(33_399_524, 12647) + // Standard Error: 662 + .saturating_add(Weight::from_ref_time(64_466).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 100]`. + fn remove_vote(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_029 nanoseconds. + Weight::from_parts(23_451_700, 8946) + // Standard Error: 1_028 + .saturating_add(Weight::from_ref_time(80_162).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 100]`. + fn remove_other_vote(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 21_149 nanoseconds. + Weight::from_parts(23_859_703, 8946) + // Standard Error: 1_119 + .saturating_add(Weight::from_ref_time(79_988).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/runtime/development/src/weights/pallet_elections_phragmen.rs b/runtime/development/src/weights/pallet_elections_phragmen.rs new file mode 100644 index 0000000000..e799c7e9ca --- /dev/null +++ b/runtime/development/src/weights/pallet_elections_phragmen.rs @@ -0,0 +1,277 @@ + +//! Autogenerated weights for `pallet_elections_phragmen` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_elections_phragmen +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_elections_phragmen.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_elections_phragmen`. +pub struct WeightInfo(PhantomData); +impl pallet_elections_phragmen::WeightInfo for WeightInfo { + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[1, 16]`. + fn vote_equal(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `527 + v * (80 ±0)` + // Estimated: `9838 + v * (320 ±0)` + // Minimum execution time: 35_186 nanoseconds. + Weight::from_parts(36_352_142, 9838) + // Standard Error: 2_665 + .saturating_add(Weight::from_ref_time(107_010).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_more(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `495 + v * (80 ±0)` + // Estimated: `9710 + v * (320 ±0)` + // Minimum execution time: 49_242 nanoseconds. + Weight::from_parts(50_009_408, 9710) + // Standard Error: 11_445 + .saturating_add(Weight::from_ref_time(197_853).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_less(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `527 + v * (80 ±0)` + // Estimated: `9838 + v * (320 ±0)` + // Minimum execution time: 48_580 nanoseconds. + Weight::from_parts(51_296_612, 9838) + // Standard Error: 13_325 + .saturating_add(Weight::from_ref_time(53_074).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + fn remove_voter() -> Weight { + // Proof Size summary in bytes: + // Measured: `1017` + // Estimated: `7266` + // Minimum execution time: 45_424 nanoseconds. + Weight::from_parts(46_366_000, 7266) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 100]`. + fn submit_candidacy(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1635 + c * (48 ±0)` + // Estimated: `6390 + c * (144 ±0)` + // Minimum execution time: 40_004 nanoseconds. + Weight::from_parts(40_085_331, 6390) + // Standard Error: 1_696 + .saturating_add(Weight::from_ref_time(110_947).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 100]`. + fn renounce_candidacy_candidate(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `414 + c * (48 ±0)` + // Estimated: `895 + c * (48 ±0)` + // Minimum execution time: 36_227 nanoseconds. + Weight::from_parts(36_822_873, 895) + // Standard Error: 1_582 + .saturating_add(Weight::from_ref_time(65_167).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_members() -> Weight { + // Proof Size summary in bytes: + // Measured: `1783` + // Estimated: `10895` + // Minimum execution time: 54_161 nanoseconds. + Weight::from_parts(55_463_000, 10895) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_runners_up() -> Weight { + // Proof Size summary in bytes: + // Measured: `1086` + // Estimated: `1581` + // Minimum execution time: 38_781 nanoseconds. + Weight::from_parts(39_984_000, 1581) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 500_000_000 nanoseconds. + Weight::from_ref_time(500_000_000_000) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn remove_member_with_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `1918` + // Estimated: `16776` + // Minimum execution time: 81_662 nanoseconds. + Weight::from_parts(82_394_000, 16776) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: Elections Voting (r:1001 w:1000) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1000 w:1000) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `v` is `[500, 1000]`. + /// The range of component `d` is `[0, 500]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `3863 + v * (873 ±0)` + // Estimated: `19504 + v * (12348 ±0)` + // Minimum execution time: 42_583_168 nanoseconds. + Weight::from_parts(42_678_065_000, 19504) + // Standard Error: 375_836 + .saturating_add(Weight::from_ref_time(52_817_230).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12348).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1001 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:83 w:83) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 100]`. + /// The range of component `v` is `[1, 1000]`. + /// The range of component `e` is `[1000, 16000]`. + fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + v * (636 ±0) + e * (28 ±0)` + // Estimated: `530640 + v * (5450 ±6) + e * (106 ±0) + c * (2372 ±3)` + // Minimum execution time: 3_929_077 nanoseconds. + Weight::from_parts(3_943_132_000, 530640) + // Standard Error: 487_751 + .saturating_add(Weight::from_ref_time(24_453_668).saturating_mul(v.into())) + // Standard Error: 31_301 + .saturating_add(Weight::from_ref_time(862_064).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(25)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5450).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(106).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2372).saturating_mul(c.into())) + } +} diff --git a/runtime/development/src/weights/pallet_fees.rs b/runtime/development/src/weights/pallet_fees.rs index 7b1e8ad14f..18fe99143a 100644 --- a/runtime/development/src/weights/pallet_fees.rs +++ b/runtime/development/src/weights/pallet_fees.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_fees + +//! Autogenerated weights for `pallet_fees` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_fees @@ -16,22 +19,26 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_fees.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_fees.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_fees using the Substrate node and recommended hardware. +/// Weight functions for `pallet_fees`. pub struct WeightInfo(PhantomData); -impl pallet_fees::weights::WeightInfo for WeightInfo { +impl pallet_fees::WeightInfo for WeightInfo { + /// Storage: Fees FeeBalances (r:0 w:1) + /// Proof: Fees FeeBalances (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn set_fee() -> Weight { - Weight::from_ref_time(23_692_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_212 nanoseconds. + Weight::from_ref_time(12_674_000) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_identity.rs b/runtime/development/src/weights/pallet_identity.rs new file mode 100644 index 0000000000..a0bed33c34 --- /dev/null +++ b/runtime/development/src/weights/pallet_identity.rs @@ -0,0 +1,320 @@ + +//! Autogenerated weights for `pallet_identity` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_identity +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_identity.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_identity`. +pub struct WeightInfo(PhantomData); +impl pallet_identity::WeightInfo for WeightInfo { + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 19]`. + fn add_registrar(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `63 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 17_473 nanoseconds. + Weight::from_parts(18_369_416, 1636) + // Standard Error: 2_030 + .saturating_add(Weight::from_ref_time(104_517).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[0, 100]`. + fn set_identity(r: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `473 + r * (5 ±0)` + // Estimated: `10013` + // Minimum execution time: 40_556 nanoseconds. + Weight::from_parts(39_921_550, 10013) + // Standard Error: 2_599 + .saturating_add(Weight::from_ref_time(84_294).saturating_mul(r.into())) + // Standard Error: 507 + .saturating_add(Weight::from_ref_time(590_284).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 100]`. + fn set_subs_new(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `100` + // Estimated: `15746 + s * (2589 ±0)` + // Minimum execution time: 12_733 nanoseconds. + Weight::from_parts(29_224_855, 15746) + // Standard Error: 4_247 + .saturating_add(Weight::from_ref_time(4_289_100).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// The range of component `p` is `[0, 100]`. + fn set_subs_old(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `225 + p * (32 ±0)` + // Estimated: `15746` + // Minimum execution time: 12_884 nanoseconds. + Weight::from_parts(28_093_250, 15746) + // Standard Error: 3_656 + .saturating_add(Weight::from_ref_time(1_747_551).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. + fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `532 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `15746` + // Minimum execution time: 69_469 nanoseconds. + Weight::from_parts(39_531_473, 15746) + // Standard Error: 1_256 + .saturating_add(Weight::from_ref_time(1_735_690).saturating_mul(s.into())) + // Standard Error: 1_256 + .saturating_add(Weight::from_ref_time(326_164).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[0, 100]`. + fn request_judgement(r: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `430 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 40_936 nanoseconds. + Weight::from_parts(39_012_552, 11649) + // Standard Error: 5_967 + .saturating_add(Weight::from_ref_time(146_018).saturating_mul(r.into())) + // Standard Error: 1_164 + .saturating_add(Weight::from_ref_time(635_596).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 20]`. + /// The range of component `x` is `[0, 100]`. + fn cancel_request(r: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `429 + x * (66 ±0)` + // Estimated: `10013` + // Minimum execution time: 37_049 nanoseconds. + Weight::from_parts(36_361_530, 10013) + // Standard Error: 5_794 + .saturating_add(Weight::from_ref_time(76_744).saturating_mul(r.into())) + // Standard Error: 1_130 + .saturating_add(Weight::from_ref_time(632_161).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 19]`. + fn set_fee(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 10_550 nanoseconds. + Weight::from_parts(11_027_512, 1636) + // Standard Error: 1_346 + .saturating_add(Weight::from_ref_time(80_626).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 19]`. + fn set_account_id(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_738 nanoseconds. + Weight::from_parts(10_347_983, 1636) + // Standard Error: 1_009 + .saturating_add(Weight::from_ref_time(69_102).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 19]`. + fn set_fields(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `120 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 9_658 nanoseconds. + Weight::from_parts(9_971_967, 1636) + // Standard Error: 1_052 + .saturating_add(Weight::from_ref_time(73_458).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 19]`. + /// The range of component `x` is `[0, 100]`. + fn provide_judgement(r: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `508 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 31_008 nanoseconds. + Weight::from_parts(29_685_247, 11649) + // Standard Error: 6_315 + .saturating_add(Weight::from_ref_time(121_805).saturating_mul(r.into())) + // Standard Error: 1_168 + .saturating_add(Weight::from_ref_time(1_011_953).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + /// The range of component `x` is `[0, 100]`. + fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `892 + r * (15 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `20952` + // Minimum execution time: 92_482 nanoseconds. + Weight::from_parts(61_391_463, 20952) + // Standard Error: 7_976 + .saturating_add(Weight::from_ref_time(97_443).saturating_mul(r.into())) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(1_773_014).saturating_mul(s.into())) + // Standard Error: 1_557 + .saturating_add(Weight::from_ref_time(323_185).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 99]`. + fn add_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `506 + s * (36 ±0)` + // Estimated: `18335` + // Minimum execution time: 37_289 nanoseconds. + Weight::from_parts(41_999_609, 18335) + // Standard Error: 1_216 + .saturating_add(Weight::from_ref_time(75_273).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// The range of component `s` is `[1, 100]`. + fn rename_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `622 + s * (3 ±0)` + // Estimated: `12602` + // Minimum execution time: 16_290 nanoseconds. + Weight::from_parts(20_452_207, 12602) + // Standard Error: 3_339 + .saturating_add(Weight::from_ref_time(17_119).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// The range of component `s` is `[1, 100]`. + fn remove_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `701 + s * (35 ±0)` + // Estimated: `18335` + // Minimum execution time: 40_656 nanoseconds. + Weight::from_parts(43_935_052, 18335) + // Standard Error: 1_065 + .saturating_add(Weight::from_ref_time(62_066).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 99]`. + fn quit_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `627 + s * (37 ±0)` + // Estimated: `8322` + // Minimum execution time: 27_552 nanoseconds. + Weight::from_parts(29_791_045, 8322) + // Standard Error: 986 + .saturating_add(Weight::from_ref_time(63_817).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/runtime/development/src/weights/pallet_interest_accrual.rs b/runtime/development/src/weights/pallet_interest_accrual.rs new file mode 100644 index 0000000000..ffd4bf0940 --- /dev/null +++ b/runtime/development/src/weights/pallet_interest_accrual.rs @@ -0,0 +1,44 @@ + +//! Autogenerated weights for `pallet_interest_accrual` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_interest_accrual +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_interest_accrual.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_interest_accrual`. +pub struct WeightInfo(PhantomData); +impl pallet_interest_accrual::WeightInfo for WeightInfo { + /// The range of component `n` is `[1, 25]`. + fn calculate_accumulated_rate(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 671 nanoseconds. + Weight::from_ref_time(181_268) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(645_249).saturating_mul(n.into())) + } +} diff --git a/runtime/development/src/weights/pallet_keystore.rs b/runtime/development/src/weights/pallet_keystore.rs index e036c4501e..88bffeb7ce 100644 --- a/runtime/development/src/weights/pallet_keystore.rs +++ b/runtime/development/src/weights/pallet_keystore.rs @@ -1,55 +1,82 @@ -//! Autogenerated weights for pallet_keystore + +//! Autogenerated weights for `pallet_keystore` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-06-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 -// --pallet=pallet-keystore +// --pallet=pallet_keystore // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./runtime/development/src/weights/pallet_keystore.rs -// --template=./scripts/frame-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_keystore.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_keystore using the Substrate node and recommended -/// hardware. +/// Weight functions for `pallet_keystore`. pub struct WeightInfo(PhantomData); -impl pallet_keystore::weights::WeightInfo for WeightInfo { - fn add_keys(n: u32) -> Weight { - Weight::from_ref_time(26_305_000) // Standard Error: 166_000 - .saturating_add(Weight::from_ref_time(33_062_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) +impl pallet_keystore::WeightInfo for WeightInfo { + /// Storage: Keystore KeyDeposit (r:1 w:0) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) + /// Storage: Keystore LastKeyByPurpose (r:0 w:1) + /// Proof: Keystore LastKeyByPurpose (max_values: None, max_size: Some(97), added: 2572, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + fn add_keys(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `3114 + n * (2595 ±0)` + // Minimum execution time: 37_820 nanoseconds. + Weight::from_parts(17_122_053, 3114) + // Standard Error: 11_215 + .saturating_add(Weight::from_ref_time(22_611_583).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - - fn revoke_keys(n: u32) -> Weight { - Weight::from_ref_time(12_542_000) // Standard Error: 105_000 - .saturating_add(Weight::from_ref_time(18_740_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) + /// Storage: Keystore Keys (r:10 w:10) + /// Proof: Keystore Keys (max_values: None, max_size: Some(120), added: 2595, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + fn revoke_keys(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `148 + n * (75 ±0)` + // Estimated: `0 + n * (2595 ±0)` + // Minimum execution time: 21_890 nanoseconds. + Weight::from_ref_time(10_946_013) + // Standard Error: 12_666 + .saturating_add(Weight::from_ref_time(12_587_510).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2595).saturating_mul(n.into())) } - + /// Storage: Keystore KeyDeposit (r:0 w:1) + /// Proof: Keystore KeyDeposit (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_deposit() -> Weight { - Weight::from_ref_time(20_999_000).saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_722 nanoseconds. + Weight::from_ref_time(11_993_000) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_loans.rs b/runtime/development/src/weights/pallet_loans.rs index d6ab221f41..8d398a8a30 100644 --- a/runtime/development/src/weights/pallet_loans.rs +++ b/runtime/development/src/weights/pallet_loans.rs @@ -2,19 +2,24 @@ //! Autogenerated weights for `pallet_loans` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-09, STEPS: `2`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `MBP-de-Luis.home`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --pallet=pallet-loans -// --chain -// centrifuge +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_loans // --extrinsic=* -// --output=runtime/centrifuge/src/weights/pallet_loans.rs +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_loans.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -26,77 +31,265 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_loans`. pub struct WeightInfo(PhantomData); impl pallet_loans::WeightInfo for WeightInfo { - fn update_portfolio_valuation(n: u32) -> Weight { - Weight::from_ref_time(31_740_408) // Standard Error: 4_421 - .saturating_add(Weight::from_ref_time(5_889_944).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Loans LastLoanId (r:1 w:1) + /// Proof: Loans LastLoanId (max_values: None, max_size: Some(32), added: 2507, mode: MaxEncodedLen) + /// Storage: Loans CreatedLoan (r:0 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) fn create() -> Weight { - Weight::from_ref_time(55_000_000) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + // Proof Size summary in bytes: + // Measured: `1200` + // Estimated: `14271` + // Minimum execution time: 78_445 nanoseconds. + Weight::from_parts(80_269_000, 14271) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) } - - fn borrow(n: u32) -> Weight { - Weight::from_ref_time(89_980_992) // Standard Error: 6_031 - .saturating_add(Weight::from_ref_time(339_355).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) + /// Storage: Loans CreatedLoan (r:1 w:1) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn borrow(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `38172 + n * (340 ±0)` + // Estimated: `406331` + // Minimum execution time: 227_263 nanoseconds. + Weight::from_parts(253_204_926, 406331) + // Standard Error: 60_800 + .saturating_add(Weight::from_ref_time(821_079).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)) } - - fn repay(n: u32) -> Weight { - Weight::from_ref_time(88_057_556) // Standard Error: 9_218 - .saturating_add(Weight::from_ref_time(296_755).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn repay(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `38228 + n * (340 ±0)` + // Estimated: `403628` + // Minimum execution time: 169_776 nanoseconds. + Weight::from_parts(191_203_662, 403628) + // Standard Error: 53_978 + .saturating_add(Weight::from_ref_time(113_323).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) } - - fn write_off(n: u32) -> Weight { - Weight::from_ref_time(50_179_983) // Standard Error: 1_760 - .saturating_add(Weight::from_ref_time(299_592).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn write_off(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `41236 + n * (340 ±0)` + // Estimated: `400130` + // Minimum execution time: 325_475 nanoseconds. + Weight::from_parts(350_248_170, 400130) + // Standard Error: 109_838 + .saturating_add(Weight::from_ref_time(964_862).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) } - - fn admin_write_off(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:1 w:0) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn admin_write_off(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `41487 + n * (340 ±0)` + // Estimated: `402833` + // Minimum execution time: 327_749 nanoseconds. + Weight::from_parts(370_644_004, 402833) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } - - fn close(n: u32) -> Weight { - Weight::from_ref_time(55_882_678) // Standard Error: 7_625 - .saturating_add(Weight::from_ref_time(338_879).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn propose_loan_mutation(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `937 + n * (316 ±0)` + // Estimated: `331707` + // Minimum execution time: 47_298 nanoseconds. + Weight::from_parts(59_693_193, 331707) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) } - - fn propose_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: InterestAccrual LastUpdated (r:1 w:0) + /// Proof: InterestAccrual LastUpdated (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn apply_loan_mutation(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `37573 + n * (340 ±0)` + // Estimated: `403476` + // Minimum execution time: 105_336 nanoseconds. + Weight::from_parts(114_925_228, 403476) + // Standard Error: 60_749 + .saturating_add(Weight::from_ref_time(665_077).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } - - fn apply_loan_mutation(n: u32) -> Weight { - Weight::from_ref_time(63_153_708) // Standard Error: 2_472 - .saturating_add(Weight::from_ref_time(325_868).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + /// Storage: Loans CreatedLoan (r:1 w:0) + /// Proof: Loans CreatedLoan (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:1) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:1) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Loans ClosedLoan (r:0 w:1) + /// Proof: Loans ClosedLoan (max_values: None, max_size: Some(264), added: 2739, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 9]`. + fn close(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `37335 + n * (349 ±0)` + // Estimated: `372971` + // Minimum execution time: 127_888 nanoseconds. + Weight::from_parts(143_685_633, 372971) + // Standard Error: 67_849 + .saturating_add(Weight::from_ref_time(1_624_004).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(7)) } - + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: PoolSystem NotedChange (r:0 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) fn propose_write_off_policy() -> Weight { - Weight::from_ref_time(27_000_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `512` + // Estimated: `6494` + // Minimum execution time: 88_714 nanoseconds. + Weight::from_parts(90_268_000, 6494) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: PoolSystem NotedChange (r:1 w:1) + /// Proof: PoolSystem NotedChange (max_values: None, max_size: Some(5184), added: 7659, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) fn apply_write_off_policy() -> Weight { - Weight::from_ref_time(27_000_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `4950` + // Estimated: `10947` + // Minimum execution time: 92_231 nanoseconds. + Weight::from_parts(93_674_000, 10947) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: InterestAccrual Rates (r:1 w:0) + /// Proof: InterestAccrual Rates (max_values: Some(1), max_size: Some(36002), added: 36497, mode: MaxEncodedLen) + /// Storage: PriceCollector Collection (r:1 w:0) + /// Proof: PriceCollector Collection (max_values: None, max_size: Some(37026), added: 39501, mode: MaxEncodedLen) + /// Storage: Loans ActiveLoans (r:1 w:0) + /// Proof: Loans ActiveLoans (max_values: None, max_size: Some(326026), added: 328501, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:0 w:1) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + fn update_portfolio_valuation(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `36994 + n * (316 ±0)` + // Estimated: `408290` + // Minimum execution time: 93_484 nanoseconds. + Weight::from_parts(90_559_384, 408290) + // Standard Error: 44_883 + .saturating_add(Weight::from_ref_time(10_213_860).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_migration_manager.rs b/runtime/development/src/weights/pallet_migration_manager.rs index 3e89c52a99..2774f4727d 100644 --- a/runtime/development/src/weights/pallet_migration_manager.rs +++ b/runtime/development/src/weights/pallet_migration_manager.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_migration_manager + +//! Autogenerated weights for `pallet_migration_manager` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_migration_manager @@ -16,56 +19,95 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_migration_manager.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_migration_manager.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_migration_manager using the Substrate node and -/// recommended hardware. +/// Weight functions for `pallet_migration_manager`. pub struct WeightInfo(PhantomData); -impl pallet_migration_manager::weights::WeightInfo for WeightInfo { +impl pallet_migration_manager::WeightInfo for WeightInfo { + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn finalize() -> Weight { - Weight::from_ref_time(26_615_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `496` + // Minimum execution time: 17_212 nanoseconds. + Weight::from_parts(17_723_000, 496) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - - fn migrate_system_account(n: u32) -> Weight { - Weight::from_ref_time(27_663_000) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_582_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: System Account (r:0 w:100) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 100]`. + fn migrate_system_account(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 18_645 nanoseconds. + Weight::from_parts(18_361_813, 496) + // Standard Error: 1_647 + .saturating_add(Weight::from_ref_time(1_082_059).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } - + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn migrate_balances_issuance() -> Weight { - Weight::from_ref_time(34_731_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 19_366 nanoseconds. + Weight::from_parts(19_897_000, 496) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - - fn migrate_vesting_vesting(n: u32) -> Weight { - Weight::from_ref_time(120_260_000) // Standard Error: 359_000 - .saturating_add(Weight::from_ref_time(54_192_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Vesting Vesting (r:10 w:10) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:10 w:10) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:10 w:10) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + fn migrate_vesting_vesting(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `363 + n * (461 ±0)` + // Estimated: `496 + n * (9009 ±0)` + // Minimum execution time: 66_404 nanoseconds. + Weight::from_parts(33_512_133, 496) + // Standard Error: 83_617 + .saturating_add(Weight::from_ref_time(36_066_009).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(9009).saturating_mul(n.into())) } - - fn migrate_proxy_proxies(n: u32) -> Weight { - Weight::from_ref_time(99_970_000) // Standard Error: 172_000 - .saturating_add(Weight::from_ref_time(10_752_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) + /// Storage: Migration Status (r:1 w:1) + /// Proof: Migration Status (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Proxy Proxies (r:0 w:10) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 10]`. + fn migrate_proxy_proxies(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `496` + // Minimum execution time: 35_276 nanoseconds. + Weight::from_parts(36_808_128, 496) + // Standard Error: 76_342 + .saturating_add(Weight::from_ref_time(7_400_912).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } } diff --git a/runtime/development/src/weights/pallet_multisig.rs b/runtime/development/src/weights/pallet_multisig.rs new file mode 100644 index 0000000000..25a548cb6e --- /dev/null +++ b/runtime/development/src/weights/pallet_multisig.rs @@ -0,0 +1,139 @@ + +//! Autogenerated weights for `pallet_multisig` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_multisig +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_multisig.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_multisig`. +pub struct WeightInfo(PhantomData); +impl pallet_multisig::WeightInfo for WeightInfo { + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 17_002 nanoseconds. + Weight::from_ref_time(17_991_010) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(462).saturating_mul(z.into())) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_create(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 49_753 nanoseconds. + Weight::from_parts(42_172_090, 5821) + // Standard Error: 856 + .saturating_add(Weight::from_ref_time(93_901).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_764).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 35_125 nanoseconds. + Weight::from_parts(28_524_177, 5821) + // Standard Error: 674 + .saturating_add(Weight::from_ref_time(84_976).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(1_707).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `550 + s * (33 ±0)` + // Estimated: `8424` + // Minimum execution time: 57_507 nanoseconds. + Weight::from_parts(47_349_367, 8424) + // Standard Error: 1_179 + .saturating_add(Weight::from_ref_time(122_246).saturating_mul(s.into())) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(1_733).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_create(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `426 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 38_322 nanoseconds. + Weight::from_parts(40_334_565, 5821) + // Standard Error: 1_057 + .saturating_add(Weight::from_ref_time(94_166).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_approve(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `5821` + // Minimum execution time: 25_136 nanoseconds. + Weight::from_parts(25_678_732, 5821) + // Standard Error: 1_258 + .saturating_add(Weight::from_ref_time(94_962).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// The range of component `s` is `[2, 100]`. + fn cancel_as_multi(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `616 + s * (1 ±0)` + // Estimated: `5821` + // Minimum execution time: 39_794 nanoseconds. + Weight::from_parts(41_043_473, 5821) + // Standard Error: 1_213 + .saturating_add(Weight::from_ref_time(101_266).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/development/src/weights/pallet_order_book.rs b/runtime/development/src/weights/pallet_order_book.rs index a4ef7881a2..16dedf49a9 100644 --- a/runtime/development/src/weights/pallet_order_book.rs +++ b/runtime/development/src/weights/pallet_order_book.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for `pallet_order_book` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-29, STEPS: `10`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `kf-FG`, CPU: `` +//! HOSTNAME: `kf-FG.local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 // Executed Command: @@ -12,14 +12,14 @@ // benchmark // pallet // --chain=development-local -// --steps=10 -// --repeat=1 +// --steps=50 +// --repeat=20 // --pallet=pallet-order-book // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=pallet-order-book.rs +// --output=pallet_order_book.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -40,17 +40,17 @@ impl pallet_order_book::WeightInfo for WeightInfo { /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8068), added: 10543, mode: MaxEncodedLen) /// Storage: OrderBook Orders (r:0 w:1) /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn create_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1217` - // Estimated: `8014376` - // Minimum execution time: 46_000 nanoseconds. - Weight::from_parts(46_000_000, 8014376) + // Measured: `1250` + // Estimated: `22407` + // Minimum execution time: 42_000 nanoseconds. + Weight::from_parts(42_000_000, 22407) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -66,10 +66,10 @@ impl pallet_order_book::WeightInfo for WeightInfo { /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn user_update_order() -> Weight { // Proof Size summary in bytes: - // Measured: `1722` - // Estimated: `17195` - // Minimum execution time: 40_000 nanoseconds. - Weight::from_parts(40_000_000, 17195) + // Measured: `1755` + // Estimated: `17228` + // Minimum execution time: 39_000 nanoseconds. + Weight::from_parts(39_000_000, 17228) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -78,15 +78,15 @@ impl pallet_order_book::WeightInfo for WeightInfo { /// Storage: OrmlTokens Accounts (r:1 w:1) /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8068), added: 10543, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn user_cancel_order() -> Weight { // Proof Size summary in bytes: // Measured: `1116` - // Estimated: `8007810` - // Minimum execution time: 32_000 nanoseconds. - Weight::from_parts(32_000_000, 8007810) + // Estimated: `15808` + // Minimum execution time: 30_000 nanoseconds. + Weight::from_parts(31_000_000, 15808) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -97,15 +97,15 @@ impl pallet_order_book::WeightInfo for WeightInfo { /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: OrderBook AssetPairOrders (r:1 w:1) - /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8068), added: 10543, mode: MaxEncodedLen) /// Storage: OrderBook UserOrders (r:0 w:1) /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) fn fill_order_full() -> Weight { // Proof Size summary in bytes: // Measured: `1702` - // Estimated: `8020828` + // Estimated: `28826` // Minimum execution time: 64_000 nanoseconds. - Weight::from_parts(64_000_000, 8020828) + Weight::from_parts(65_000_000, 28826) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -115,8 +115,8 @@ impl pallet_order_book::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_000 nanoseconds. - Weight::from_ref_time(9_000_000) + // Minimum execution time: 7_000 nanoseconds. + Weight::from_ref_time(8_000_000) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: OrderBook TradingPair (r:0 w:1) @@ -125,8 +125,8 @@ impl pallet_order_book::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_000 nanoseconds. - Weight::from_ref_time(9_000_000) + // Minimum execution time: 7_000 nanoseconds. + Weight::from_ref_time(8_000_000) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: OrderBook TradingPair (r:1 w:1) @@ -135,8 +135,8 @@ impl pallet_order_book::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `209` // Estimated: `2557` - // Minimum execution time: 14_000 nanoseconds. - Weight::from_parts(14_000_000, 2557) + // Minimum execution time: 11_000 nanoseconds. + Weight::from_parts(12_000_000, 2557) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/runtime/development/src/weights/pallet_permissions.rs b/runtime/development/src/weights/pallet_permissions.rs index d5123974f9..112e86ac83 100644 --- a/runtime/development/src/weights/pallet_permissions.rs +++ b/runtime/development/src/weights/pallet_permissions.rs @@ -1,14 +1,17 @@ -//! Autogenerated weights for pallet_permissions + +//! Autogenerated weights for `pallet_permissions` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: -// ./target/release/centrifuge-chain +// target/release/centrifuge-chain // benchmark -// --chain=development-local +// pallet +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_permissions @@ -16,55 +19,90 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_permissions.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_permissions.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_permissions using the Substrate node and recommended -/// hardware. +/// Weight functions for `pallet_permissions`. pub struct WeightInfo(PhantomData); -impl pallet_permissions::weights::WeightInfo for WeightInfo { +impl pallet_permissions::WeightInfo for WeightInfo { + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn add_as_admin() -> Weight { - Weight::from_ref_time(31_499_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `5224` + // Minimum execution time: 20_849 nanoseconds. + Weight::from_parts(21_610_000, 5224) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } - + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn add_as_editor() -> Weight { - Weight::from_ref_time(40_388_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `7927` + // Minimum execution time: 28_834 nanoseconds. + Weight::from_parts(29_285_000, 7927) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } - + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn remove_as_admin() -> Weight { - Weight::from_ref_time(31_735_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `162` + // Estimated: `5224` + // Minimum execution time: 24_476 nanoseconds. + Weight::from_parts(25_077_000, 5224) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } - + /// Storage: Permissions Permission (r:2 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) fn remove_as_editor() -> Weight { - Weight::from_ref_time(42_200_000) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `7927` + // Minimum execution time: 31_278 nanoseconds. + Weight::from_parts(31_940_000, 7927) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } - + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn purge() -> Weight { - Weight::from_ref_time(30_026_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 20_979 nanoseconds. + Weight::from_parts(22_192_000, 2703) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) fn admin_purge() -> Weight { - Weight::from_ref_time(30_696_000) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 21_640 nanoseconds. + Weight::from_parts(22_482_000, 2703) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_pool_registry.rs b/runtime/development/src/weights/pallet_pool_registry.rs index 672c36a77b..9d5d90a1af 100644 --- a/runtime/development/src/weights/pallet_pool_registry.rs +++ b/runtime/development/src/weights/pallet_pool_registry.rs @@ -1,69 +1,165 @@ -//! Autogenerated weights for pallet_pools + +//! Autogenerated weights for `pallet_pool_registry` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION -//! 4.0.0-dev DATE: 2022-06-29, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH -//! RANGE: `[]` EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: -//! Some("development-local"), DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 -// --pallet=pallet_pools +// --pallet=pallet_pool_registry // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_pools.rs -// --template=./scripts/runtime-weight-template.hbs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_pool_registry.rs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weights for pallet_pools using the Substrate node and recommended hardware. +/// Weight functions for `pallet_pool_registry`. pub struct WeightInfo(PhantomData); -impl pallet_pool_registry::weights::WeightInfo for WeightInfo { - fn register(n: u32) -> Weight { - Weight::from_ref_time(74_584_000) // Standard Error: 70_000 - .saturating_add(Weight::from_ref_time(536_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) +impl pallet_pool_registry::WeightInfo for WeightInfo { + /// Storage: PoolRegistry Pools (r:1 w:1) + /// Proof: PoolRegistry Pools (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:6 w:5) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: PoolSystem AccountDeposit (r:1 w:1) + /// Proof: PoolSystem AccountDeposit (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Permissions PermissionCount (r:1 w:1) + /// Proof: Permissions PermissionCount (max_values: None, max_size: Some(46), added: 2521, mode: MaxEncodedLen) + /// Storage: Permissions Permission (r:1 w:1) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: Loans WriteOffPolicy (r:0 w:1) + /// Proof: Loans WriteOffPolicy (max_values: None, max_size: Some(5126), added: 7601, mode: MaxEncodedLen) + /// Storage: PoolSystem PoolDeposit (r:0 w:1) + /// Proof: PoolSystem PoolDeposit (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 5]`. + fn register(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `675` + // Estimated: `19807 + n * (2475 ±0)` + // Minimum execution time: 153_326 nanoseconds. + Weight::from_parts(139_206_198, 19807) + // Standard Error: 188_717 + .saturating_add(Weight::from_ref_time(16_937_683).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(8)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2475).saturating_mul(n.into())) } - - fn update_no_execution(n: u32) -> Weight { - Weight::from_ref_time(28_723_000) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(224_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 5]`. + fn update_no_execution(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `819 + n * (133 ±0)` + // Estimated: `9739 + n * (2531 ±0)` + // Minimum execution time: 48_650 nanoseconds. + Weight::from_parts(48_089_534, 9739) + // Standard Error: 15_208 + .saturating_add(Weight::from_ref_time(2_369_740).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_proof_size(2531).saturating_mul(n.into())) } - - fn execute_update(n: u32) -> Weight { - Weight::from_ref_time(45_439_000) // Standard Error: 64_000 - .saturating_add(Weight::from_ref_time(1_074_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: PoolSystem ScheduledUpdate (r:0 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) + /// The range of component `n` is `[1, 5]`. + fn update_and_execute(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `910 + n * (167 ±0)` + // Estimated: `15599 + n * (2699 ±0)` + // Minimum execution time: 83_606 nanoseconds. + Weight::from_parts(77_925_350, 15599) + // Standard Error: 37_965 + .saturating_add(Weight::from_ref_time(8_314_113).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2699).saturating_mul(n.into())) } - - fn update_and_execute(n: u32) -> Weight { - Weight::from_ref_time(47_712_000) // Standard Error: 28_000 - .saturating_add(Weight::from_ref_time(876_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem ScheduledUpdate (r:1 w:1) + /// Proof: PoolSystem ScheduledUpdate (max_values: None, max_size: Some(1019), added: 3494, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:0) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:1) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// The range of component `n` is `[1, 5]`. + fn execute_update(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `932 + n * (194 ±0)` + // Estimated: `16412 + n * (2725 ±0)` + // Minimum execution time: 72_314 nanoseconds. + Weight::from_parts(66_320_482, 16412) + // Standard Error: 41_355 + .saturating_add(Weight::from_ref_time(8_428_684).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2725).saturating_mul(n.into())) } - - fn set_metadata(n: u32) -> Weight { - Weight::from_ref_time(35_549_000) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_000).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolRegistry PoolMetadata (r:0 w:1) + /// Proof: PoolRegistry PoolMetadata (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 46]`. + fn set_metadata(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `146` + // Estimated: `2703` + // Minimum execution time: 22_411 nanoseconds. + Weight::from_parts(23_553_917, 2703) + // Standard Error: 1_161 + .saturating_add(Weight::from_ref_time(5_442).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/runtime/development/src/weights/pallet_pool_system.rs b/runtime/development/src/weights/pallet_pool_system.rs index bc00dc42c4..9a17b23b30 100644 --- a/runtime/development/src/weights/pallet_pool_system.rs +++ b/runtime/development/src/weights/pallet_pool_system.rs @@ -2,15 +2,16 @@ //! Autogenerated weights for `pallet_pool_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-16, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `branan-laptop`, CPU: `Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=altair-dev +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_pool_system @@ -18,7 +19,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/altair/src/weights/pallet_pool_system.rs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_pool_system.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -30,121 +31,201 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_pool_system`. pub struct WeightInfo(PhantomData); impl pallet_pool_system::WeightInfo for WeightInfo { - // Storage: Permissions Permission (r:1 w:0) - // Storage: PoolSystem Pool (r:1 w:1) + /// Storage: Permissions Permission (r:1 w:0) + /// Proof: Permissions Permission (max_values: None, max_size: Some(228), added: 2703, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) fn set_max_reserve() -> Weight { - // Minimum execution time: 50_133 nanoseconds. - Weight::from_ref_time(50_853_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `657` + // Estimated: `5991` + // Minimum execution time: 29_746 nanoseconds. + Weight::from_parts(30_197_000, 5991) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PoolNAV (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:5 w:0) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_orders(n: u32, ) -> Weight { - // Minimum execution time: 129_749 nanoseconds. - Weight::from_ref_time(76_600_951 as u64) - // Standard Error: 237_997 - .saturating_add(Weight::from_ref_time(81_306_778 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((8 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((8 as u64).saturating_mul(n as u64))) + // Proof Size summary in bytes: + // Measured: `841 + n * (133 ±0)` + // Estimated: `33561 + n * (20298 ±0)` + // Minimum execution time: 121_947 nanoseconds. + Weight::from_parts(50_340_346, 33561) + // Standard Error: 43_332 + .saturating_add(Weight::from_ref_time(74_108_151).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PoolNAV (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:0) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_no_execution(n: u32, ) -> Weight { - // Minimum execution time: 97_132 nanoseconds. - Weight::from_ref_time(72_455_912 as u64) - // Standard Error: 187_107 - .saturating_add(Weight::from_ref_time(35_517_413 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((6 as u64).saturating_mul(n as u64))) + // Proof Size summary in bytes: + // Measured: `1007 + n * (133 ±0)` + // Estimated: `33561 + n * (17694 ±0)` + // Minimum execution time: 83_635 nanoseconds. + Weight::from_parts(54_862_697, 33561) + // Standard Error: 34_507 + .saturating_add(Weight::from_ref_time(31_508_266).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17694).saturating_mul(n.into())) } - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: PoolSystem EpochExecution (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Loans PoolNAV (r:1 w:0) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:1) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: PoolSystem EpochExecution (r:1 w:0) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Loans PortfolioValuation (r:1 w:0) + /// Proof: Loans PortfolioValuation (max_values: None, max_size: Some(24050), added: 26525, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:5 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:5) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:5) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn close_epoch_execute(n: u32, ) -> Weight { - // Minimum execution time: 213_668 nanoseconds. - Weight::from_ref_time(180_152_377 as u64) - // Standard Error: 287_491 - .saturating_add(Weight::from_ref_time(83_097_282 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((8 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(7 as u64)) - .saturating_add(T::DbWeight::get().writes((8 as u64).saturating_mul(n as u64))) + // Proof Size summary in bytes: + // Measured: `1525 + n * (133 ±0)` + // Estimated: `43975 + n * (20298 ±0)` + // Minimum execution time: 209_289 nanoseconds. + Weight::from_parts(138_046_977, 43975) + // Standard Error: 59_696 + .saturating_add(Weight::from_ref_time(75_664_781).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(20298).saturating_mul(n.into())) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:0) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:0) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn submit_solution(n: u32, ) -> Weight { - // Minimum execution time: 44_135 nanoseconds. - Weight::from_ref_time(50_755_813 as u64) - // Standard Error: 87_780 - .saturating_add(Weight::from_ref_time(1_507_903 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `493 + n * (249 ±0)` + // Estimated: `6533` + // Minimum execution time: 30_777 nanoseconds. + Weight::from_parts(31_524_649, 6533) + // Standard Error: 13_304 + .saturating_add(Weight::from_ref_time(771_497).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: PoolSystem EpochExecution (r:1 w:1) - // Storage: PoolSystem Pool (r:1 w:1) - // Storage: Investments InProcessingInvestOrders (r:1 w:1) - // Storage: OrmlTokens Accounts (r:3 w:3) - // Storage: System Account (r:2 w:2) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: Investments InvestOrderId (r:1 w:0) - // Storage: Investments ActiveInvestOrders (r:1 w:1) - // Storage: Investments InProcessingRedeemOrders (r:1 w:1) - // Storage: Investments RedeemOrderId (r:1 w:0) - // Storage: Investments ActiveRedeemOrders (r:1 w:1) - // Storage: Timestamp Now (r:1 w:0) - // Storage: Investments ClearedInvestOrders (r:0 w:1) - // Storage: Investments ClearedRedeemOrders (r:0 w:1) + /// Storage: PoolSystem EpochExecution (r:1 w:1) + /// Proof: PoolSystem EpochExecution (max_values: None, max_size: Some(770), added: 3245, mode: MaxEncodedLen) + /// Storage: PoolSystem Pool (r:1 w:1) + /// Proof: PoolSystem Pool (max_values: None, max_size: Some(813), added: 3288, mode: MaxEncodedLen) + /// Storage: Investments InProcessingInvestOrders (r:5 w:5) + /// Proof: Investments InProcessingInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:7 w:3) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Investments InvestOrderId (r:5 w:0) + /// Proof: Investments InvestOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveInvestOrders (r:5 w:5) + /// Proof: Investments ActiveInvestOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments InProcessingRedeemOrders (r:5 w:5) + /// Proof: Investments InProcessingRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Investments RedeemOrderId (r:5 w:0) + /// Proof: Investments RedeemOrderId (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Investments ActiveRedeemOrders (r:5 w:5) + /// Proof: Investments ActiveRedeemOrders (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Investments ClearedInvestOrders (r:0 w:5) + /// Proof: Investments ClearedInvestOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Investments ClearedRedeemOrders (r:0 w:5) + /// Proof: Investments ClearedRedeemOrders (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 5]`. fn execute_epoch(n: u32, ) -> Weight { - // Minimum execution time: 183_949 nanoseconds. - Weight::from_ref_time(155_991_216 as u64) - // Standard Error: 477_479 - .saturating_add(Weight::from_ref_time(64_133_550 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(8 as u64)) - .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - .saturating_add(T::DbWeight::get().writes((6 as u64).saturating_mul(n as u64))) + // Proof Size summary in bytes: + // Measured: `1503 + n * (605 ±0)` + // Estimated: `19974 + n * (17774 ±0)` + // Minimum execution time: 175_236 nanoseconds. + Weight::from_parts(124_344_158, 19974) + // Standard Error: 43_193 + .saturating_add(Weight::from_ref_time(54_899_238).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(8)) + .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17774).saturating_mul(n.into())) } } diff --git a/runtime/development/src/weights/pallet_preimage.rs b/runtime/development/src/weights/pallet_preimage.rs new file mode 100644 index 0000000000..3d871bfc0b --- /dev/null +++ b/runtime/development/src/weights/pallet_preimage.rs @@ -0,0 +1,187 @@ + +//! Autogenerated weights for `pallet_preimage` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_preimage.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_preimage`. +pub struct WeightInfo(PhantomData); +impl pallet_preimage::WeightInfo for WeightInfo { + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 4194304]`. + fn note_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `209` + // Estimated: `2566` + // Minimum execution time: 36_317 nanoseconds. + Weight::from_parts(82_180_035, 2566) + // Standard Error: 18 + .saturating_add(Weight::from_ref_time(2_389).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 4194304]`. + fn note_requested_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 23_804 nanoseconds. + Weight::from_parts(1_075_216, 2566) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(2_539).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 4194304]`. + fn note_no_deposit_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 22_502 nanoseconds. + Weight::from_parts(22_822_000, 2566) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(2_481).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + fn unnote_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `2566` + // Minimum execution time: 53_900 nanoseconds. + Weight::from_parts(57_466_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + fn unnote_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 35_747 nanoseconds. + Weight::from_parts(41_898_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn request_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `254` + // Estimated: `2566` + // Minimum execution time: 33_192 nanoseconds. + Weight::from_parts(35_406_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn request_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 22_562 nanoseconds. + Weight::from_parts(25_358_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn request_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `2566` + // Minimum execution time: 21_160 nanoseconds. + Weight::from_parts(22_351_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn request_requested_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_333 nanoseconds. + Weight::from_parts(13_284_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + fn unrequest_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `2566` + // Minimum execution time: 39_734 nanoseconds. + Weight::from_parts(43_110_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn unrequest_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_663 nanoseconds. + Weight::from_parts(14_076_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn unrequest_multi_referenced_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `2566` + // Minimum execution time: 12_323 nanoseconds. + Weight::from_parts(13_255_000, 2566) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/development/src/weights/pallet_proxy.rs b/runtime/development/src/weights/pallet_proxy.rs new file mode 100644 index 0000000000..8d6bd87d05 --- /dev/null +++ b/runtime/development/src/weights/pallet_proxy.rs @@ -0,0 +1,197 @@ + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_proxy +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_proxy.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 22_162 nanoseconds. + Weight::from_parts(23_207_581, 3716) + // Standard Error: 1_644 + .saturating_add(Weight::from_ref_time(48_182).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `650 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 47_579 nanoseconds. + Weight::from_parts(47_977_353, 11027) + // Standard Error: 2_247 + .saturating_add(Weight::from_ref_time(174_754).saturating_mul(a.into())) + // Standard Error: 2_321 + .saturating_add(Weight::from_ref_time(35_796).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 28_593 nanoseconds. + Weight::from_parts(29_844_862, 7311) + // Standard Error: 1_743 + .saturating_add(Weight::from_ref_time(177_203).saturating_mul(a.into())) + // Standard Error: 1_801 + .saturating_add(Weight::from_ref_time(2_655).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `533 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 28_463 nanoseconds. + Weight::from_parts(29_753_645, 7311) + // Standard Error: 1_779 + .saturating_add(Weight::from_ref_time(181_206).saturating_mul(a.into())) + // Standard Error: 1_839 + .saturating_add(Weight::from_ref_time(6_354).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `582 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 40_064 nanoseconds. + Weight::from_parts(41_776_629, 11027) + // Standard Error: 2_262 + .saturating_add(Weight::from_ref_time(174_192).saturating_mul(a.into())) + // Standard Error: 2_337 + .saturating_add(Weight::from_ref_time(36_204).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_138 nanoseconds. + Weight::from_parts(32_270_293, 3716) + // Standard Error: 1_752 + .saturating_add(Weight::from_ref_time(59_420).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 31_108 nanoseconds. + Weight::from_parts(32_301_855, 3716) + // Standard Error: 1_597 + .saturating_add(Weight::from_ref_time(64_128).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `259 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 24_976 nanoseconds. + Weight::from_parts(25_932_811, 3716) + // Standard Error: 1_377 + .saturating_add(Weight::from_ref_time(43_231).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `239` + // Estimated: `3716` + // Minimum execution time: 34_284 nanoseconds. + Weight::from_parts(35_197_303, 3716) + // Standard Error: 1_443 + .saturating_add(Weight::from_ref_time(18_362).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `296 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 25_999 nanoseconds. + Weight::from_parts(26_856_655, 3716) + // Standard Error: 1_466 + .saturating_add(Weight::from_ref_time(47_371).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/development/src/weights/pallet_restricted_tokens.rs b/runtime/development/src/weights/pallet_restricted_tokens.rs index f260d7e940..22124344e3 100644 --- a/runtime/development/src/weights/pallet_restricted_tokens.rs +++ b/runtime/development/src/weights/pallet_restricted_tokens.rs @@ -2,15 +2,16 @@ //! Autogenerated weights for `pallet_restricted_tokens` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner`, CPU: `Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("altair-dev"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_restricted_tokens @@ -18,7 +19,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/altair/src/weights/pallet_restricted_tokens.rs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_restricted_tokens.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -30,80 +31,126 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_restricted_tokens`. pub struct WeightInfo(PhantomData); impl pallet_restricted_tokens::WeightInfo for WeightInfo { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_native() -> Weight { - // Minimum execution time: 80_301 nanoseconds. - Weight::from_ref_time(81_201_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 54_401 nanoseconds. + Weight::from_parts(54_932_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_other() -> Weight { - // Minimum execution time: 83_801 nanoseconds. - Weight::from_ref_time(84_702_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 56_395 nanoseconds. + Weight::from_parts(56_996_000, 7811) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_native() -> Weight { - // Minimum execution time: 72_701 nanoseconds. - Weight::from_ref_time(73_601_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 47_158 nanoseconds. + Weight::from_parts(48_039_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive_other() -> Weight { - // Minimum execution time: 78_001 nanoseconds. - Weight::from_ref_time(78_802_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `438` + // Estimated: `7811` + // Minimum execution time: 52_206 nanoseconds. + Weight::from_parts(53_319_000, 7811) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_native() -> Weight { - // Minimum execution time: 83_901 nanoseconds. - Weight::from_ref_time(85_301_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 57_527 nanoseconds. + Weight::from_parts(58_819_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all_other() -> Weight { - // Minimum execution time: 88_401 nanoseconds. - Weight::from_ref_time(89_401_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 59_250 nanoseconds. + Weight::from_parts(60_302_000, 7811) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_native() -> Weight { - // Minimum execution time: 80_501 nanoseconds. - Weight::from_ref_time(81_402_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `224` + // Estimated: `2603` + // Minimum execution time: 53_970 nanoseconds. + Weight::from_parts(54_811_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:2 w:2) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:2 w:2) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer_other() -> Weight { - // Minimum execution time: 84_001 nanoseconds. - Weight::from_ref_time(85_302_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `573` + // Estimated: `7811` + // Minimum execution time: 55_873 nanoseconds. + Weight::from_parts(57_136_000, 7811) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_native() -> Weight { - // Minimum execution time: 82_701 nanoseconds. - Weight::from_ref_time(83_801_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `89` + // Estimated: `2603` + // Minimum execution time: 51_626 nanoseconds. + Weight::from_parts(53_179_000, 2603) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: OrmlTokens Accounts (r:1 w:1) - // Storage: OrmlTokens TotalIssuance (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrmlTokens TotalIssuance (r:1 w:1) + /// Proof: OrmlTokens TotalIssuance (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_other() -> Weight { - // Minimum execution time: 94_102 nanoseconds. - Weight::from_ref_time(95_601_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `7731` + // Minimum execution time: 69_349 nanoseconds. + Weight::from_parts(70_301_000, 7731) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/runtime/development/src/weights/pallet_scheduler.rs b/runtime/development/src/weights/pallet_scheduler.rs new file mode 100644 index 0000000000..9d56d8aa9d --- /dev/null +++ b/runtime/development/src/weights/pallet_scheduler.rs @@ -0,0 +1,176 @@ + +//! Autogenerated weights for `pallet_scheduler` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_scheduler +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_scheduler.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_scheduler`. +pub struct WeightInfo(PhantomData); +impl pallet_scheduler::WeightInfo for WeightInfo { + /// Storage: Scheduler IncompleteSince (r:1 w:1) + /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn service_agendas_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `31` + // Estimated: `499` + // Minimum execution time: 5_630 nanoseconds. + Weight::from_parts(5_811_000, 499) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 50]`. + fn service_agenda_base(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 5_410 nanoseconds. + Weight::from_parts(8_102_685, 41438) + // Standard Error: 4_303 + .saturating_add(Weight::from_ref_time(1_192_507).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn service_task_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_666 nanoseconds. + Weight::from_ref_time(8_957_000) + } + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `245 + s * (1 ±0)` + // Estimated: `5286 + s * (1 ±0)` + // Minimum execution time: 28_773 nanoseconds. + Weight::from_parts(29_204_000, 5286) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_091).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) + } + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + fn service_task_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_931 nanoseconds. + Weight::from_ref_time(11_271_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn service_task_periodic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_656 nanoseconds. + Weight::from_ref_time(8_896_000) + } + fn execute_dispatch_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_338 nanoseconds. + Weight::from_ref_time(4_539_000) + } + fn execute_dispatch_unsigned() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_248 nanoseconds. + Weight::from_ref_time(4_498_000) + } + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 49]`. + fn schedule(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 19_406 nanoseconds. + Weight::from_parts(22_600_153, 41438) + // Standard Error: 3_883 + .saturating_add(Weight::from_ref_time(1_218_595).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// The range of component `s` is `[1, 50]`. + fn cancel(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `110 + s * (177 ±0)` + // Estimated: `41438` + // Minimum execution time: 25_216 nanoseconds. + Weight::from_parts(22_494_611, 41438) + // Standard Error: 5_203 + .saturating_add(Weight::from_ref_time(2_198_733).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// The range of component `s` is `[0, 49]`. + fn schedule_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `287 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 24_385 nanoseconds. + Weight::from_parts(28_285_732, 43961) + // Standard Error: 4_563 + .saturating_add(Weight::from_ref_time(1_241_067).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// The range of component `s` is `[1, 50]`. + fn cancel_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `313 + s * (185 ±0)` + // Estimated: `43961` + // Minimum execution time: 27_231 nanoseconds. + Weight::from_parts(25_659_328, 43961) + // Standard Error: 5_187 + .saturating_add(Weight::from_ref_time(2_210_158).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/runtime/development/src/weights/pallet_session.rs b/runtime/development/src/weights/pallet_session.rs index 30def542df..bca728fa42 100644 --- a/runtime/development/src/weights/pallet_session.rs +++ b/runtime/development/src/weights/pallet_session.rs @@ -2,15 +2,16 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Williams-Laptop.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 // Executed Command: // target/release/centrifuge-chain // benchmark // pallet -// --chain=development-local +// --chain=centrifuge-dev // --steps=50 // --repeat=20 // --pallet=pallet_session @@ -18,7 +19,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=/tmp/runtime/development/src/weights/pallet_session.rs +// --output=/tmp/runtime/centrifuge/src/weights/pallet_session.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -30,20 +31,30 @@ use sp_std::marker::PhantomData; /// Weight functions for `pallet_session`. pub struct WeightInfo(PhantomData); impl pallet_session::WeightInfo for WeightInfo { - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:1 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:1 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { - // Minimum execution time: 23_000 nanoseconds. - Weight::from_ref_time(23_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `369` + // Estimated: `5688` + // Minimum execution time: 26_319 nanoseconds. + Weight::from_parts(26_960_000, 5688) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:0 w:1) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:1) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { - // Minimum execution time: 18_000 nanoseconds. - Weight::from_ref_time(19_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Proof Size summary in bytes: + // Measured: `418` + // Estimated: `3311` + // Minimum execution time: 19_136 nanoseconds. + Weight::from_parts(19_627_000, 3311) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/runtime/development/src/weights/pallet_timestamp.rs b/runtime/development/src/weights/pallet_timestamp.rs new file mode 100644 index 0000000000..3ad903c802 --- /dev/null +++ b/runtime/development/src/weights/pallet_timestamp.rs @@ -0,0 +1,54 @@ + +//! Autogenerated weights for `pallet_timestamp` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_timestamp +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_timestamp.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Aura CurrentSlot (r:1 w:0) + /// Proof: Aura CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `1006` + // Minimum execution time: 13_505 nanoseconds. + Weight::from_parts(14_156_000, 1006) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `0` + // Minimum execution time: 6_452 nanoseconds. + Weight::from_ref_time(6_733_000) + } +} diff --git a/runtime/development/src/weights/pallet_transfer_allowlist.rs b/runtime/development/src/weights/pallet_transfer_allowlist.rs index 7cbf162636..d8d013e205 100644 --- a/runtime/development/src/weights/pallet_transfer_allowlist.rs +++ b/runtime/development/src/weights/pallet_transfer_allowlist.rs @@ -94,6 +94,14 @@ impl pallet_transfer_allowlist::WeightInfo for WeightIn } // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) + fn remove_transfer_allowance_missing_allowance() -> Weight { + // Minimum execution time: 26_000 nanoseconds. + Weight::from_ref_time(27_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: TransferAllowList AccountCurrencyTransferCountDelay (r:1 w:0) + // Storage: TransferAllowList AccountCurrencyTransferAllowance (r:1 w:1) fn remove_transfer_allowance_delay_present() -> Weight { // Minimum execution time: 26_000 nanoseconds. Weight::from_ref_time(27_000_000) diff --git a/runtime/development/src/weights/pallet_treasury.rs b/runtime/development/src/weights/pallet_treasury.rs new file mode 100644 index 0000000000..3bae6e1a89 --- /dev/null +++ b/runtime/development/src/weights/pallet_treasury.rs @@ -0,0 +1,118 @@ + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_treasury +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_treasury.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_treasury`. +pub struct WeightInfo(PhantomData); +impl pallet_treasury::WeightInfo for WeightInfo { + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 311 nanoseconds. + Weight::from_ref_time(391_000) + } + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + fn propose_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `499` + // Minimum execution time: 33_593 nanoseconds. + Weight::from_parts(35_014_000, 499) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn reject_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `500` + // Estimated: `7789` + // Minimum execution time: 51_636 nanoseconds. + Weight::from_parts(52_649_000, 7789) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// The range of component `p` is `[0, 99]`. + fn approve_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `501 + p * (8 ±0)` + // Estimated: `3480` + // Minimum execution time: 14_577 nanoseconds. + Weight::from_parts(18_158_350, 3480) + // Standard Error: 1_368 + .saturating_add(Weight::from_ref_time(53_682).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + fn remove_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `897` + // Minimum execution time: 11_231 nanoseconds. + Weight::from_parts(11_522_000, 897) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:100 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// The range of component `p` is `[0, 100]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `290 + p * (151 ±0)` + // Estimated: `4522 + p * (2583 ±0)` + // Minimum execution time: 41_407 nanoseconds. + Weight::from_parts(39_128_676, 4522) + // Standard Error: 7_831 + .saturating_add(Weight::from_ref_time(3_744_536).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_proof_size(2583).saturating_mul(p.into())) + } +} diff --git a/runtime/development/src/weights/pallet_uniques.rs b/runtime/development/src/weights/pallet_uniques.rs new file mode 100644 index 0000000000..a5198896e8 --- /dev/null +++ b/runtime/development/src/weights/pallet_uniques.rs @@ -0,0 +1,418 @@ + +//! Autogenerated weights for `pallet_uniques` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_uniques +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_uniques.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_uniques`. +pub struct WeightInfo(PhantomData); +impl pallet_uniques::WeightInfo for WeightInfo { + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2657` + // Minimum execution time: 37_099 nanoseconds. + Weight::from_parts(38_051_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2657` + // Minimum execution time: 22_001 nanoseconds. + Weight::from_parts(23_043_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1001 w:1000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:0 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:0 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1000) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:0 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + /// The range of component `m` is `[0, 1000]`. + /// The range of component `a` is `[0, 1000]`. + fn destroy(n: u32, m: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `543 + n * (121 ±0) + m * (69 ±0) + a * (346 ±0)` + // Estimated: `5270 + n * (2613 ±0)` + // Minimum execution time: 3_092_729 nanoseconds. + Weight::from_parts(3_157_930_000, 5270) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(13_415_711).saturating_mul(n.into())) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(79_883).saturating_mul(m.into())) + // Standard Error: 34_786 + .saturating_add(Weight::from_ref_time(754_538).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(n.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:1 w:0) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `7773` + // Minimum execution time: 44_463 nanoseconds. + Weight::from_parts(45_435_000, 7773) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 45_465 nanoseconds. + Weight::from_parts(46_346_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 36_708 nanoseconds. + Weight::from_parts(37_470_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:5000 w:5000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `852 + i * (121 ±0)` + // Estimated: `2657 + i * (2613 ±0)` + // Minimum execution time: 20_338 nanoseconds. + Weight::from_parts(20_619_000, 2657) + // Standard Error: 17_567 + .saturating_add(Weight::from_ref_time(20_039_440).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(2613).saturating_mul(i.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 25_197 nanoseconds. + Weight::from_parts(25_948_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 24_816 nanoseconds. + Weight::from_parts(25_767_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn freeze_collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_244 nanoseconds. + Weight::from_parts(19_156_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn thaw_collection() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 18_525 nanoseconds. + Weight::from_parts(18_986_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:2) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `463` + // Estimated: `5188` + // Minimum execution time: 29_224 nanoseconds. + Weight::from_parts(29_855_000, 5188) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 19_226 nanoseconds. + Weight::from_parts(19_677_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + fn force_item_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `2657` + // Minimum execution time: 22_912 nanoseconds. + Weight::from_parts(23_554_000, 2657) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) + fn set_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `8543` + // Minimum execution time: 52_367 nanoseconds. + Weight::from_parts(53_359_000, 8543) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(605), added: 3080, mode: MaxEncodedLen) + fn clear_attribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `1501` + // Estimated: `8543` + // Minimum execution time: 50_173 nanoseconds. + Weight::from_parts(51_286_000, 8543) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + fn set_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `451` + // Estimated: `5463` + // Minimum execution time: 37_420 nanoseconds. + Weight::from_parts(38_081_000, 5463) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(331), added: 2806, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `838` + // Estimated: `5463` + // Minimum execution time: 38_371 nanoseconds. + Weight::from_parts(39_043_000, 5463) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) + fn set_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5431` + // Minimum execution time: 36_998 nanoseconds. + Weight::from_parts(37_570_000, 5431) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(299), added: 2774, mode: MaxEncodedLen) + fn clear_collection_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `740` + // Estimated: `5431` + // Minimum execution time: 35_075 nanoseconds. + Weight::from_parts(35_977_000, 5431) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5270` + // Minimum execution time: 25_527 nanoseconds. + Weight::from_parts(26_119_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `612` + // Estimated: `5270` + // Minimum execution time: 25_638 nanoseconds. + Weight::from_parts(25_979_000, 5270) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + fn set_accept_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2531` + // Minimum execution time: 20_518 nanoseconds. + Weight::from_parts(20_939_000, 2531) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques CollectionMaxSupply (r:1 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + fn set_collection_max_supply() -> Weight { + // Proof Size summary in bytes: + // Measured: `385` + // Estimated: `5160` + // Minimum execution time: 21_870 nanoseconds. + Weight::from_parts(22_752_000, 5160) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Asset (r:1 w:0) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + fn set_price() -> Weight { + // Proof Size summary in bytes: + // Measured: `374` + // Estimated: `2613` + // Minimum execution time: 21_751 nanoseconds. + Weight::from_parts(22_431_000, 2613) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(138), added: 2613, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:1 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(105), added: 2580, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(182), added: 2657, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(104), added: 2579, mode: MaxEncodedLen) + fn buy_item() -> Weight { + // Proof Size summary in bytes: + // Measured: `739` + // Estimated: `7850` + // Minimum execution time: 51_215 nanoseconds. + Weight::from_parts(52_518_000, 7850) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/runtime/development/src/weights/pallet_utility.rs b/runtime/development/src/weights/pallet_utility.rs new file mode 100644 index 0000000000..b12401b8be --- /dev/null +++ b/runtime/development/src/weights/pallet_utility.rs @@ -0,0 +1,78 @@ + +//! Autogenerated weights for `pallet_utility` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_utility +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_utility.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_utility`. +pub struct WeightInfo(PhantomData); +impl pallet_utility::WeightInfo for WeightInfo { + /// The range of component `c` is `[0, 1000]`. + fn batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_209 nanoseconds. + Weight::from_ref_time(9_129_306) + // Standard Error: 2_960 + .saturating_add(Weight::from_ref_time(8_226_140).saturating_mul(c.into())) + } + fn as_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_564 nanoseconds. + Weight::from_ref_time(8_155_000) + } + /// The range of component `c` is `[0, 1000]`. + fn batch_all(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_599 nanoseconds. + Weight::from_ref_time(16_307_821) + // Standard Error: 3_188 + .saturating_add(Weight::from_ref_time(8_619_470).saturating_mul(c.into())) + } + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_976 nanoseconds. + Weight::from_ref_time(14_467_000) + } + /// The range of component `c` is `[0, 1000]`. + fn force_batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_249 nanoseconds. + Weight::from_ref_time(6_571_875) + // Standard Error: 3_073 + .saturating_add(Weight::from_ref_time(8_206_947).saturating_mul(c.into())) + } +} diff --git a/runtime/development/src/weights/pallet_vesting.rs b/runtime/development/src/weights/pallet_vesting.rs new file mode 100644 index 0000000000..3909302f87 --- /dev/null +++ b/runtime/development/src/weights/pallet_vesting.rs @@ -0,0 +1,190 @@ + +//! Autogenerated weights for `pallet_vesting` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=centrifuge-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_vesting +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=/tmp/runtime/centrifuge/src/weights/pallet_vesting.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_vesting`. +pub struct WeightInfo(PhantomData); +impl pallet_vesting::WeightInfo for WeightInfo { + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 3]`. + fn vest_locked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `331 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `6406` + // Minimum execution time: 35_025 nanoseconds. + Weight::from_parts(36_030_255, 6406) + // Standard Error: 1_480 + .saturating_add(Weight::from_ref_time(45_905).saturating_mul(l.into())) + // Standard Error: 28_359 + .saturating_add(Weight::from_ref_time(272_959).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 3]`. + fn vest_unlocked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `331 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `6406` + // Minimum execution time: 35_816 nanoseconds. + Weight::from_parts(36_422_112, 6406) + // Standard Error: 1_586 + .saturating_add(Weight::from_ref_time(38_024).saturating_mul(l.into())) + // Standard Error: 30_391 + .saturating_add(Weight::from_ref_time(247_015).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 3]`. + fn vest_other_locked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `466 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_183 nanoseconds. + Weight::from_parts(39_397_996, 9009) + // Standard Error: 3_031 + .saturating_add(Weight::from_ref_time(50_274).saturating_mul(l.into())) + // Standard Error: 58_087 + .saturating_add(Weight::from_ref_time(343_961).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[1, 3]`. + fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `466 + l * (25 ±0) + s * (37 ±0)` + // Estimated: `9009` + // Minimum execution time: 38_331 nanoseconds. + Weight::from_parts(40_150_426, 9009) + // Standard Error: 3_074 + .saturating_add(Weight::from_ref_time(40_543).saturating_mul(l.into())) + // Standard Error: 58_899 + .saturating_add(Weight::from_ref_time(202_467).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 2]`. + fn vested_transfer(_l: u32, _s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + l * (25 ±0) + s * (332 ±0)` + // Estimated: `9009` + // Minimum execution time: 59_550 nanoseconds. + Weight::from_parts(75_086_515, 9009) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[0, 2]`. + fn force_vested_transfer(_l: u32, _s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `120 + l * (25 ±0) + s * (332 ±0)` + // Estimated: `11612` + // Minimum execution time: 63_668 nanoseconds. + Weight::from_parts(79_421_584, 11612) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 3]`. + fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_253 nanoseconds. + Weight::from_parts(41_451_758, 9009) + // Standard Error: 3_869 + .saturating_add(Weight::from_ref_time(42_606).saturating_mul(l.into())) + // Standard Error: 123_401 + .saturating_add(Weight::from_ref_time(240_899).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(157), added: 2632, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 3]`. + fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `467 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9009` + // Minimum execution time: 39_083 nanoseconds. + Weight::from_parts(41_148_427, 9009) + // Standard Error: 4_532 + .saturating_add(Weight::from_ref_time(43_606).saturating_mul(l.into())) + // Standard Error: 144_557 + .saturating_add(Weight::from_ref_time(368_102).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/runtime/development/src/xcm.rs b/runtime/development/src/xcm.rs index 340033dbeb..9dc1863bcb 100644 --- a/runtime/development/src/xcm.rs +++ b/runtime/development/src/xcm.rs @@ -9,34 +9,38 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. - use cfg_primitives::{ - constants::currency_decimals, parachains, types::{EnsureRootOr, HalfOfCouncil}, }; +use cfg_traits::TryConvert; pub use cfg_types::tokens::CurrencyId; +use cfg_types::EVMChainId; pub use cumulus_primitives_core::ParaId; pub use frame_support::{ parameter_types, traits::{Contains, Everything, Get, Nothing}, weights::Weight, }; -use frame_support::{sp_std::marker::PhantomData, traits::fungibles}; +use frame_support::{ + sp_std::marker::PhantomData, + traits::{fungibles, fungibles::Mutate}, +}; use orml_asset_registry::{AssetRegistryTrader, FixedRateAssetRegistryTrader}; -use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key, MultiCurrency}; +use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; use orml_xcm_support::MultiNativeAsset; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use runtime_common::{ - xcm::{general_key, AccountIdToMultiLocation, FixedConversionRateProvider}, - xcm_fees::{default_per_second, ksm_per_second, native_per_second}, + xcm::{general_key, AccountIdToMultiLocation, FixedConversionRateProvider, LpInstanceRelayer}, + xcm_fees::native_per_second, }; use sp_core::ConstU32; use sp_runtime::traits::{Convert, Zero}; +pub use xcm::v3::{MultiAsset, MultiLocation}; use xcm::{latest::Weight as XcmWeight, prelude::*}; use xcm_builder::{ - Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, @@ -45,10 +49,41 @@ use xcm_builder::{ use xcm_executor::{traits::JustTry, XcmExecutor}; use super::{ - AccountId, Balance, OrmlAssetRegistry, OrmlTokens, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, + AccountId, Balance, OrmlAssetRegistry, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, Tokens, TreasuryAccount, XcmpQueue, }; +/// A call filter for the XCM Transact instruction. This is a temporary +/// measure until we properly account for proof size weights. +/// +/// Calls that are allowed through this filter must: +/// 1. Have a fixed weight; +/// 2. Cannot lead to another call being made; +/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call +/// parameters. +/// +/// NOTE: Defensive configuration for now, inspired by filter of +/// SystemParachains and Polkadot, can be extended if desired. +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::Timestamp(..) + | RuntimeCall::Balances(..) + | RuntimeCall::Utility(pallet_utility::Call::as_derivative { .. }) + | RuntimeCall::PolkadotXcm( + pallet_xcm::Call::limited_reserve_transfer_assets { .. } + ) | RuntimeCall::XcmpQueue(..) + | RuntimeCall::DmpQueue(..) + | RuntimeCall::Proxy(..) + | RuntimeCall::LiquidityPoolsGateway( + pallet_liquidity_pools_gateway::Call::process_msg { .. } + ) | RuntimeCall::OrderBook(..) + ) + } +} + /// The main XCM config /// This is where we configure the core of our XCM integrations: how tokens are /// transferred, how fees are calculated, what barriers we impose on incoming @@ -72,7 +107,7 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = crate::AllPalletsWithSystem; type ResponseHandler = PolkadotXcm; type RuntimeCall = RuntimeCall; - type SafeCallFilter = Everything; + type SafeCallFilter = SafeCallFilter; type SubscriptionService = PolkadotXcm; type Trader = Trader; type UniversalAliases = Nothing; @@ -104,27 +139,6 @@ parameter_types! { 0, ); - pub NativePerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2(Parachain(ParachainInfo::parachain_id().into()), general_key(parachains::kusama::altair::AIR_KEY)), - ).into(), - native_per_second(), - ); - - pub KsmPerSecond: (AssetId, u128) = (MultiLocation::parent().into(), ksm_per_second()); - - pub AUSDPerSecond: (AssetId, u128) = ( - MultiLocation::new( - 1, - X2( - Parachain(parachains::kusama::karura::ID), - general_key(parachains::kusama::karura::AUSD_KEY) - ) - ).into(), - default_per_second(currency_decimals::AUSD) - ); - } pub struct ToTreasury; @@ -140,7 +154,7 @@ impl TakeRevenue for ToTreasury { if let Ok(currency_id) = >::convert(location) { - let _ = OrmlTokens::deposit(currency_id, &TreasuryAccount::get(), amount); + let _ = Tokens::mint_into(currency_id, &TreasuryAccount::get(), amount); } } } @@ -197,44 +211,41 @@ where /// This type implements conversions from our `CurrencyId` type into /// `MultiLocation` and vice-versa. A currency locally is identified with a /// `CurrencyId` variant but in the network it is identified in the form of a -/// `MultiLocation`, in this case a pair (Para-Id, Currency-Id). +/// `MultiLocation`. pub struct CurrencyIdConvert; /// Convert our `CurrencyId` type into its `MultiLocation` representation. -/// Other chains need to know how this conversion takes place in order to -/// handle it on their side. +/// We use the `OrmlAssetRegistry` to lookup the associated `MultiLocation` for +/// any given `CurrencyId`, while blocking tokens that are not Xcm-transferable. impl Convert> for CurrencyIdConvert { fn convert(id: CurrencyId) -> Option { - match id { - CurrencyId::Tranche(_, _) => None, - _ => OrmlAssetRegistry::multilocation(&id).ok()?, - } + OrmlAssetRegistry::metadata(id) + .filter(|m| m.additional.transferability.includes_xcm()) + .and_then(|m| m.location) + .and_then(|l| l.try_into().ok()) } } -/// Convert an incoming `MultiLocation` into a `CurrencyId` if possible. -/// Here we need to know the canonical representation of all the tokens we -/// handle in order to correctly convert their `MultiLocation` representation -/// into our internal `CurrencyId` type. +/// Convert an incoming `MultiLocation` into a `CurrencyId` through a +/// reverse-lookup using the OrmlAssetRegistry. In the registry, we register CFG +/// using its absolute, non-anchored MultliLocation so we need to unanchor the +/// input location for Centrifuge-native assets for that to work. impl xcm_executor::traits::Convert for CurrencyIdConvert { fn convert(location: MultiLocation) -> Result { - match location { + let unanchored_location = match location { MultiLocation { + parents: 0, + interior, + } => MultiLocation { parents: 1, - interior: X3(Parachain(para_id), PalletInstance(_), GeneralKey { .. }), - } => match para_id { - // Note: Until we have pools on Centrifuge, we don't know the pools pallet index - // and can't therefore match specifically on the Tranche tokens' multilocation; - // However, we can preemptively assume that any Centrifuge X3-based asset refers - // to a Tranche token and explicitly fail its conversion to avoid Tranche tokens - // from being transferred through XCM without permission checks. This is fine since - // we don't have any other native token represented as an X3 neither do we plan to. - id if id == u32::from(ParachainInfo::get()) => Err(location), - // Still support X3-based MultiLocations native to other chains - _ => OrmlAssetRegistry::location_to_asset_id(location).ok_or(location), + interior: interior + .pushed_front_with(Parachain(u32::from(ParachainInfo::get()))) + .map_err(|_| location)?, }, - _ => OrmlAssetRegistry::location_to_asset_id(location).ok_or(location), - } + x => x, + }; + + OrmlAssetRegistry::location_to_asset_id(unanchored_location).ok_or(location) } } @@ -271,7 +282,7 @@ impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type SendXcmOrigin = EnsureXcmOrigin; - type SovereignAccountOf = (); + type SovereignAccountOf = LocationToAccountId; type TrustedLockers = (); type UniversalLocation = UniversalLocation; type Weigher = FixedWeightBounds; @@ -286,8 +297,7 @@ impl pallet_xcm::Config for Runtime { } parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); @@ -305,9 +315,8 @@ pub type LocationToAccountId = ( // If we receive a MultiLocation of type AccountId32 that is within Centrifuge, // just alias it to a local [AccountId]. AccountId32Aliases, - // A wildcard MultiLocation to AccountId conversion for all the other MultiLocations - // within the same Relay network. - Account32Hash, + // Generate remote accounts according to polkadot standards + cfg_primitives::xcm::HashedDescriptionDescribeFamilyAllTerminal, ); /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -322,11 +331,31 @@ pub type XcmRouter = ( XcmpQueue, ); +const MOONBASE_ALPHA_PARA_ID: u32 = 1000; +/// https://chainlist.org/chain/1287 +const MOONBASE_ALPHA_EVM_ID: u64 = 1282; + +/// A constant way of mapping parachain IDs to EVM-chain IDs +pub struct ParaToEvm; +impl TryConvert for ParaToEvm { + type Error = cfg_types::ParaId; + + fn try_convert(a: cfg_types::ParaId) -> Result { + // NOTE: Currently only supported moonbeam + match a { + MOONBASE_ALPHA_PARA_ID => Ok(MOONBASE_ALPHA_EVM_ID), + _ => Err(a), + } + } +} + /// This is the type we use to convert an (incoming) XCM origin into a local /// `Origin` instance, ready for dispatching a transaction with Xcm's /// `Transact`. There is an `OriginKind` which can biases the kind of local /// `Origin` it will become. pub type XcmOriginToTransactDispatchOrigin = ( + // A matcher that catches all Moonbeam relaying contracts to generate the right Origin + LpInstanceRelayer, // Sovereign account converter; this attempts to derive an `AccountId` from the origin location // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for // foreign chains who want to have a local sovereign account on this chain which they control. diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index 818fd98c7f..e3975b8c3d 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -90,6 +90,7 @@ cfg-utils = { path = "../../libs/utils" } ethereum = { version = "0.14.0", default-features = false } +pallet-ethereum = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } pallet-evm = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } pallet-evm-chain-id = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } diff --git a/runtime/integration-tests/src/ethereum_transaction/pallet.rs b/runtime/integration-tests/src/ethereum_transaction/pallet.rs index 1b33f58624..92713adfac 100644 --- a/runtime/integration-tests/src/ethereum_transaction/pallet.rs +++ b/runtime/integration-tests/src/ethereum_transaction/pallet.rs @@ -15,7 +15,7 @@ use cfg_traits::ethereum::EthereumTransactor; use ethereum::{LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2}; use frame_support::{assert_err, dispatch::RawOrigin}; use fudge::primitives::Chain; -use pallet_evm::FeeCalculator; +use pallet_evm::{ExitReason, ExitReason::Succeed, ExitSucceed, FeeCalculator}; use runtime_common::account_conversion::AccountConverter; use sp_core::{Get, H160, U256}; use tokio::runtime::Handle; @@ -80,6 +80,28 @@ async fn call() { }) .unwrap(); + let t_hash = { + let nonce = env + .with_state(Chain::Para(PARA_ID), || { + pallet_ethereum_transaction::Pallet::::nonce() + }) + .unwrap(); + + let signature = + pallet_ethereum_transaction::Pallet::::get_transaction_signature().unwrap(); + + TransactionV2::Legacy(LegacyTransaction { + nonce, + gas_price: U256::from(1), + gas_limit: U256::from(0x100000), + action: TransactionAction::Call(contract_address), + value: U256::zero(), + input: foo.as_slice().into(), + signature, + }) + .hash() + }; + // Executing Foo should be OK and emit an event with the value returned by the // function. env.with_mut_state(Chain::Para(PARA_ID), || { @@ -95,15 +117,24 @@ async fn call() { }) .unwrap(); + let reason = ExitReason::Succeed(ExitSucceed::Returned); + env::evolve_until_event_is_found!( env, Chain::Para(PARA_ID), RuntimeEvent, 5, - RuntimeEvent::EthereumTransaction(pallet_ethereum_transaction::Event::Executed { - value, - .. - }) if [ hex::encode(value) == "0000000000000000000000000000000000000000000000000000000000000001" ], + RuntimeEvent::Ethereum(pallet_ethereum::Event::Executed { + from, + to, + transaction_hash, + exit_reason + }) if [ + from == &sender_address + && to == &contract_address + && transaction_hash == &t_hash + && exit_reason == &reason + ], ); // Executing Bar should error out since the function returns an error. @@ -117,7 +148,8 @@ async fn call() { U256::from(0x100000), ); - assert!(res.is_err()); + // NOTE: WE CAN NOTE CHECK WHETHER THE EVM ERRORS OUT + assert!(res.is_ok()); }) .unwrap(); } diff --git a/runtime/integration-tests/src/liquidity_pools/gateway.rs b/runtime/integration-tests/src/liquidity_pools/gateway.rs index f3fc62fe04..3b61179791 100644 --- a/runtime/integration-tests/src/liquidity_pools/gateway.rs +++ b/runtime/integration-tests/src/liquidity_pools/gateway.rs @@ -24,8 +24,8 @@ use frame_support::{ }; use fudge::primitives::Chain; use liquidity_pools_gateway_routers::{ - axelar_evm::AxelarEVMRouter, ethereum_xcm::EthereumXCMRouter, DomainRouter, EVMChain, - EVMDomain, FeeValues, XCMRouter, XcmDomain, XcmTransactInfo, + axelar_evm::AxelarEVMRouter, ethereum_xcm::EthereumXCMRouter, DomainRouter, EVMDomain, + FeeValues, XCMRouter, XcmDomain, XcmTransactInfo, }; use orml_traits::asset_registry::AssetMetadata; use pallet_democracy::{AccountVote, Conviction, ReferendumIndex, Vote, VoteThreshold}; @@ -100,8 +100,10 @@ async fn set_router() { ethereum_xcm_transact_call_index: bounded_vec![0], contract_address: H160::from_low_u64_be(3), max_gas_limit: 10, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id, - fee_per_second: 1u128, + fee_amount: 0, }; let ethereum_xcm_router = EthereumXCMRouter:: { @@ -249,7 +251,7 @@ async fn process_msg() { env.with_state(Chain::Para(PARA_ID), || { assert_noop!( pallet_liquidity_pools_gateway::Pallet::::process_msg( - GatewayOrigin::Local(test_instance).into(), + GatewayOrigin::Domain(test_instance).into(), gateway_msg, ), pallet_liquidity_pools::Error::::InvalidIncomingMessage, diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/mod.rs index 34f13591a7..17909ac383 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/mod.rs @@ -1,3 +1,4 @@ mod setup; mod test_net; mod tests; +mod transfers; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index 2c9508c78e..ec38b159be 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -222,7 +222,9 @@ fn update_member() { assert_ok!(Permissions::add( RuntimeOrigin::signed(ALICE.into()), Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(new_member.clone()), + AccountConverter::::convert( + new_member.clone() + ), PermissionScope::Pool(pool_id), Role::PoolRole(PoolRole::TrancheInvestor( default_tranche_id(pool_id), @@ -233,7 +235,9 @@ fn update_member() { // Verify the Investor role was set as expected in Permissions assert!(Permissions::has( PermissionScope::Pool(pool_id), - AccountConverter::::convert(new_member.clone()), + AccountConverter::::convert( + new_member.clone() + ), Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)), )); @@ -293,10 +297,28 @@ fn add_currency() { // Enable LiquidityPools transferability enable_liquidity_pool_transferability(currency_id); + assert_eq!( + OrmlTokens::free_balance( + GLIMMER_CURRENCY_ID, + &::Sender::get() + ), + DEFAULT_BALANCE_GLMR + ); + assert_ok!(LiquidityPools::add_currency( RuntimeOrigin::signed(BOB.into()), currency_id )); + + assert_eq!( + OrmlTokens::free_balance( + GLIMMER_CURRENCY_ID, + &::Sender::get() + ), + /// Ensure it only charged the 0.2 GLMR of fee + DEFAULT_BALANCE_GLMR + - dollar(18).saturating_div(5) + ); }); } @@ -632,20 +654,6 @@ fn schedule_upgrade() { DEFAULT_BALANCE_GLMR * dollar(18), ); - // Failing because the treasury has no funds - assert_noop!( - LiquidityPools::schedule_upgrade(RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, [7; 20]), - pallet_xcm_transactor::Error::::UnableToWithdrawAsset - ); - - // The treasury needs GLRM to cover the fees of sending - // this message - OrmlTokens::deposit( - GLMR_CURRENCY_ID, - &TreasuryAccount::get(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); - // Now it finally works assert_ok!(LiquidityPools::schedule_upgrade( RuntimeOrigin::root(), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index e519003f22..493965b9a4 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -102,7 +102,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -149,7 +152,10 @@ mod same_currencies { let decrease_amount = invest_amount / 3; let final_amount = invest_amount - decrease_amount; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -220,7 +226,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -308,7 +317,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -330,9 +342,9 @@ mod same_currencies { assert_eq!(Tokens::total_issuance(investment_currency_id), 0); assert_ok!(Investments::invest_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::one(), + price: Quantity::one(), } )); assert_eq!(Tokens::total_issuance(investment_currency_id), amount); @@ -435,7 +447,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let invest_amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -454,9 +469,9 @@ mod same_currencies { assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); @@ -530,9 +545,9 @@ mod same_currencies { assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::checked_from_rational(1, 2).unwrap(), + price: Quantity::checked_from_rational(1, 2).unwrap(), } )); // Order should have been cleared by fulfilling investment @@ -649,7 +664,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; @@ -701,7 +719,10 @@ mod same_currencies { let decrease_amount = redeem_amount / 3; let final_amount = redeem_amount - decrease_amount; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -792,7 +813,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let sending_domain_locator = Domain::convert(DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain()); @@ -879,7 +903,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = @@ -902,9 +929,9 @@ mod same_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::one(), + price: Quantity::one(), } )); @@ -1013,7 +1040,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let redeem_amount = 100_000_000; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let currency_id = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; let pool_account = @@ -1035,9 +1065,9 @@ mod same_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); @@ -1103,9 +1133,9 @@ mod same_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::checked_from_rational(1, 2).unwrap(), + price: Quantity::checked_from_rational(1, 2).unwrap(), } )); // Order should have been cleared by fulfilling redemption @@ -1200,8 +1230,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let invest_amount: u128 = 100_000_000; let decrease_amount = invest_amount + 1; - let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let investor: AccountId = AccountConverter::< + DevelopmentRuntime, + LocationToAccountId, + >::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1239,8 +1271,10 @@ mod same_currencies { let pool_id = DEFAULT_POOL_ID; let redeem_amount: u128 = 100_000_000; let decrease_amount = redeem_amount + 1; - let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let investor: AccountId = AccountConverter::< + DevelopmentRuntime, + LocationToAccountId, + >::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1279,8 +1313,10 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount: u128 = 100_000_000; - let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let investor: AccountId = AccountConverter::< + DevelopmentRuntime, + LocationToAccountId, + >::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1294,9 +1330,9 @@ mod same_currencies { assert_ok!(Investments::process_invest_orders(default_investment_id())); assert_ok!(Investments::invest_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::one(), + price: Quantity::one(), } )); @@ -1339,8 +1375,10 @@ mod same_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let amount: u128 = 100_000_000; - let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + let investor: AccountId = AccountConverter::< + DevelopmentRuntime, + LocationToAccountId, + >::convert((DOMAIN_MOONBEAM, BOB)); let currency_id: CurrencyId = AUSD_CURRENCY_ID; let currency_decimals = currency_decimals::AUSD; create_currency_pool(pool_id, currency_id, currency_decimals.into()); @@ -1361,9 +1399,9 @@ mod same_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::one(), - price: Rate::one(), + price: Quantity::one(), } )); @@ -1423,7 +1461,10 @@ mod mismatching_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; let pool_currency_decimals = currency_decimals::AUSD; @@ -1618,7 +1659,10 @@ mod mismatching_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let trader: AccountId = ALICE.into(); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -1798,7 +1842,10 @@ mod mismatching_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let trader: AccountId = ALICE.into(); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -1886,9 +1933,9 @@ mod mismatching_currencies { // tokens assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); assert_eq!( @@ -1950,9 +1997,9 @@ mod mismatching_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(100), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); assert_ok!(Investments::collect_redemptions_for( @@ -2044,7 +2091,10 @@ mod mismatching_currencies { setup_pre_requirements(); let pool_id = DEFAULT_POOL_ID; let investor: AccountId = - AccountConverter::::convert((DOMAIN_MOONBEAM, BOB)); + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); let trader: AccountId = ALICE.into(); let pool_currency: CurrencyId = AUSD_CURRENCY_ID; let foreign_currency: CurrencyId = USDT_CURRENCY_ID; @@ -2153,9 +2203,9 @@ mod mismatching_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(50), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); assert_ok!(Investments::collect_redemptions_for( @@ -2209,9 +2259,9 @@ mod mismatching_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(100), - price: Rate::checked_from_rational(1, 4).unwrap(), + price: Quantity::checked_from_rational(1, 4).unwrap(), } )); assert_ok!(Investments::collect_redemptions_for( @@ -2263,9 +2313,9 @@ mod mismatching_currencies { assert_ok!(Investments::process_redeem_orders(default_investment_id())); assert_ok!(Investments::redeem_fulfillment( default_investment_id(), - FulfillmentWithPrice:: { + FulfillmentWithPrice { of_amount: Perquintill::from_percent(100), - price: Rate::checked_from_rational(2, 1).unwrap(), + price: Quantity::checked_from_rational(2, 1).unwrap(), } )); assert_ok!(Investments::collect_redemptions_for( @@ -2560,7 +2610,9 @@ mod setup { assert_eq!( Tokens::balance( default_investment_id().into(), - &AccountConverter::::convert(DEFAULT_OTHER_DOMAIN_ADDRESS) + &AccountConverter::::convert( + DEFAULT_OTHER_DOMAIN_ADDRESS + ) ), 0 ); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs index d84fd80f07..3bb24f4c5b 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -72,8 +72,8 @@ use crate::{ }, utils::{AUSD_CURRENCY_ID, GLMR_CURRENCY_ID, MOONBEAM_EVM_CHAIN_ID}, }; - -pub const DEFAULT_BALANCE_GLMR: Balance = 1_000_000_000_000; +// 10 GLMR (18 decimals) +pub const DEFAULT_BALANCE_GLMR: Balance = 10_000_000_000_000_000_000; pub const DOMAIN_MOONBEAM: Domain = Domain::EVM(MOONBEAM_EVM_CHAIN_ID); pub const DEFAULT_EVM_ADDRESS_MOONBEAM: [u8; 20] = [99; 20]; pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = @@ -87,7 +87,7 @@ pub const DEFAULT_MOONBEAM_LOCATION: MultiLocation = MultiLocation { interior: X1(Parachain(PARA_ID_MOONBEAM)), }; -pub type LiquidityPoolMessage = Message; +pub type LiquidityPoolMessage = Message; pub fn get_default_moonbeam_native_token_location() -> MultiLocation { MultiLocation { @@ -107,9 +107,15 @@ pub fn set_test_domain_router( location: Box::new(xcm_domain_location), ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), contract_address: H160::from(DEFAULT_EVM_ADDRESS_MOONBEAM), - max_gas_limit: 700_000, + max_gas_limit: 500_000, + transact_required_weight_at_most: Weight::from_parts( + 12530000000, + DEFAULT_PROOF_SIZE.saturating_div(2), + ), + overall_weight: Weight::from_parts(15530000000, DEFAULT_PROOF_SIZE), fee_currency: currency_id, - fee_per_second: default_per_second(18), + // 0.2 token + fee_amount: 200000000000000000, }, _marker: Default::default(), }, @@ -160,23 +166,19 @@ pub fn setup_pre_requirements() { Some(GLMR_CURRENCY_ID) )); - // Give Alice, Bob and Treasury enough glimmer to pay for fees - OrmlTokens::deposit( - GLMR_CURRENCY_ID, - &ALICE.into(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); + // Fund the gateway sender account with enough glimmer to pay for fees OrmlTokens::deposit( - GLMR_CURRENCY_ID, - &BOB.into(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); - // Treasury pays for `Executed*` messages - OrmlTokens::deposit( - GLMR_CURRENCY_ID, - &TreasuryPalletId::get().into_account_truncating(), - DEFAULT_BALANCE_GLMR * dollar(18), + GLIMMER_CURRENCY_ID, + &::Sender::get(), + DEFAULT_BALANCE_GLMR, ); + // TODO: Check + // // Treasury pays for `Executed*` messages + // OrmlTokens::deposit( + // GLMR_CURRENCY_ID, + // &TreasuryPalletId::get().into_account_truncating(), + // DEFAULT_BALANCE_GLMR * dollar(18), + // ); // Register AUSD in the asset registry which is the default pool currency in // `create_pool` diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs index d0a3c29919..0b537b15bf 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -258,7 +258,9 @@ fn transfer_tranche_tokens_from_local() { assert_ok!(Permissions::add( RuntimeOrigin::signed(receiver.into()), Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), + AccountConverter::::convert( + dest_address.clone() + ), PermissionScope::Pool(pool_id), Role::PoolRole(PoolRole::TrancheInvestor( default_tranche_id(pool_id), @@ -417,14 +419,18 @@ fn transferring_invalid_tranche_tokens_should_fail() { assert_ok!(Permissions::add( RuntimeOrigin::signed(BOB.into()), Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), + AccountConverter::::convert( + dest_address.clone() + ), PermissionScope::Pool(invalid_pool_id), Role::PoolRole(PoolRole::TrancheInvestor(valid_tranche_id, valid_until)), )); assert_ok!(Permissions::add( RuntimeOrigin::signed(BOB.into()), Role::PoolRole(PoolRole::InvestorAdmin), - AccountConverter::::convert(dest_address.clone()), + AccountConverter::::convert( + dest_address.clone() + ), PermissionScope::Pool(valid_pool_id), Role::PoolRole(PoolRole::TrancheInvestor(invalid_tranche_id, valid_until)), )); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs index 5e3d34ba68..88fb0b1946 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs @@ -16,9 +16,9 @@ mod liquidity_pools; mod routers; /// Register AUSD in the asset registry. -/// -/// NOTE: Assumes to be executed within an externalities environment. -fn register_ausd() { +/// +/// NOTE: It should be executed within an externalities environment. +pub fn register_ausd() { let meta: AssetMetadata = AssetMetadata { decimals: 12, name: "Acala Dollar".into(), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/axelar_evm.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/axelar_evm.rs index 84cb158022..356cc62cfd 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/axelar_evm.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/axelar_evm.rs @@ -12,16 +12,20 @@ use cfg_primitives::{Balance, PoolId, TrancheId, CFG}; use cfg_traits::liquidity_pools::OutboundQueue; -use cfg_types::{domain_address::Domain, fixed_point::Rate}; +use cfg_types::{domain_address::Domain, fixed_point::Quantity}; use frame_support::{assert_ok, dispatch::RawOrigin, traits::fungible::Mutate}; use fudge::primitives::Chain; +use lazy_static::lazy_static; use liquidity_pools_gateway_routers::{ - axelar_evm::AxelarEVMRouter, DomainRouter, EVMChain, EVMDomain, EVMRouter, FeeValues, + axelar_evm::AxelarEVMRouter, DomainRouter, EVMDomain, EVMRouter, FeeValues, + MAX_AXELAR_EVM_CHAIN_SIZE, }; use pallet_evm::FeeCalculator; use pallet_liquidity_pools::Message; use runtime_common::account_conversion::AccountConverter; -use sp_core::{crypto::AccountId32, storage::Storage, Get, H160, U256}; +use sp_core::{ + bounded::BoundedVec, crypto::AccountId32, storage::Storage, ConstU32, Get, H160, U256, +}; use sp_runtime::traits::{BlakeTwo256, Hash}; use tokio::runtime::Handle; @@ -42,6 +46,14 @@ use crate::{ }, }; +lazy_static! { + pub(crate) static ref TEST_EVM_CHAIN: BoundedVec> = + BoundedVec::>::try_from( + "ethereum".as_bytes().to_vec() + ) + .unwrap(); +} + #[tokio::test] async fn submit() { let mut env = { @@ -84,7 +96,7 @@ async fn submit() { evm_domain, _marker: Default::default(), }, - evm_chain: EVMChain::Ethereum, + evm_chain: TEST_EVM_CHAIN.clone(), _marker: Default::default(), liquidity_pools_contract_address, }; @@ -118,14 +130,21 @@ async fn submit() { ); let sender = Keyring::Alice.to_account_id(); - let sender_h160: H160 = - H160::from_slice(&>::as_ref(&sender)[0..20]); + let gateway_sender = env + .with_state(Chain::Para(PARA_ID), || { + ::Sender::get() + }) + .unwrap(); + + let gateway_sender_h160: H160 = + H160::from_slice(&>::as_ref(&gateway_sender)[0..20]); - // Note how both the target address and the sender need to have some balance. + // Note how both the target address and the gateway sender need to have some + // balance. mint_balance_into_derived_account(&mut env, axelar_contract_address, 1_000_000_000 * CFG); - mint_balance_into_derived_account(&mut env, sender_h160, 1_000_000 * CFG); + mint_balance_into_derived_account(&mut env, gateway_sender_h160, 1_000_000 * CFG); - let msg = Message::::Transfer { + let msg = Message::::Transfer { currency: 0, sender: Keyring::Alice.to_account_id().into(), receiver: Keyring::Bob.to_account_id().into(), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs index ba09e1bc2d..fd9dd00c2a 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/routers/ethereum_xcm.rs @@ -19,13 +19,13 @@ use cfg_primitives::{PoolId, TrancheId}; use cfg_traits::liquidity_pools::OutboundQueue; use cfg_types::{ domain_address::Domain, - fixed_point::Rate, + fixed_point::Quantity, tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, }; use frame_support::{assert_noop, assert_ok}; use hex::FromHex; use liquidity_pools_gateway_routers::{ - ethereum_xcm::EthereumXCMRouter, AxelarXCMRouter, DomainRouter, EVMChain, EVMDomain, FeeValues, + ethereum_xcm::EthereumXCMRouter, AxelarXCMRouter, DomainRouter, EVMDomain, FeeValues, XCMRouter, XcmDomain, XcmTransactInfo, }; use orml_traits::{asset_registry::AssetMetadata, MultiCurrency}; @@ -41,14 +41,18 @@ use crate::{ liquidity_pools::pallet::development::{ setup::{dollar, ALICE, BOB, CHARLIE, PARA_ID_MOONBEAM, TEST_DOMAIN}, test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::routers::axelar_evm::TEST_EVM_CHAIN, }, utils::accounts::Keyring, }; #[test] -fn submit() { +fn submit_ethereum_xcm() { submit_test_fn(get_ethereum_xcm_router_fn()); +} +#[test] +fn submit_axelar_xcm() { submit_test_fn(get_axelar_xcm_router_fn()); } @@ -58,7 +62,7 @@ fn submit_test_fn(router_creation_fn: RouterCreationFn) { Development::execute_with(|| { setup(router_creation_fn); - let msg = Message::::Transfer { + let msg = Message::::Transfer { currency: 0, sender: ALICE.into(), receiver: BOB.into(), @@ -79,11 +83,6 @@ fn submit_test_fn(router_creation_fn: RouterCreationFn) { ), pallet_liquidity_pools_gateway::Error::::RouterNotFound, ); - - assert_noop!( - ::submit(CHARLIE.into(), TEST_DOMAIN, msg), - pallet_xcm_transactor::Error::::UnableToWithdrawAsset, - ); }); } @@ -99,12 +98,14 @@ fn get_axelar_xcm_router_fn() -> RouterCreationFn { ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), contract_address: H160::from_low_u64_be(11), max_gas_limit: 700_000, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id, - fee_per_second: default_per_second(18), + fee_amount: dollar(18).saturating_div(5), }, _marker: Default::default(), }, - axelar_target_chain: EVMChain::Ethereum, + axelar_target_chain: TEST_EVM_CHAIN.clone(), axelar_target_contract: H160::from_low_u64_be(111), _marker: Default::default(), }; @@ -124,8 +125,10 @@ fn get_ethereum_xcm_router_fn() -> RouterCreationFn { ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), contract_address: H160::from_low_u64_be(11), max_gas_limit: 700_000, + transact_required_weight_at_most: Default::default(), + overall_weight: Default::default(), fee_currency: currency_id, - fee_per_second: default_per_second(18), + fee_amount: dollar(18).saturating_div(5), }, _marker: Default::default(), }, @@ -175,15 +178,10 @@ fn setup(router_creation_fn: RouterCreationFn) { Some(glmr_currency_id) )); - // Give Alice and BOB enough glimmer to pay for fees - OrmlTokens::deposit( - glmr_currency_id, - &ALICE.into(), - 1_000_000_000_000 * dollar(18), - ); + // Fund the gateway sender account with enough glimmer to pay for fees OrmlTokens::deposit( glmr_currency_id, - &BOB.into(), + &::Sender::get(), 1_000_000_000_000 * dollar(18), ); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs new file mode 100644 index 0000000000..58103dc838 --- /dev/null +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/transfers.rs @@ -0,0 +1,245 @@ +// Copyright 2021 Development GmbH (centrifuge.io). +// This file is part of Development chain project. +// +// Development 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). +// Development is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Copyright 2021 Development GmbH (centrifuge.io). +// This file is part of Development chain project. +// +// Development 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). +// Development 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_primitives::{constants::currency_decimals, parachains, Balance}; +use cfg_types::{ + tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, + xcm::XcmMetadata, +}; +use development_runtime::{Balances, OrmlAssetRegistry, OrmlTokens, RuntimeOrigin, XTokens}; +use frame_support::assert_ok; +use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; +use runtime_common::{ + xcm::general_key, + xcm_fees::{default_per_second, ksm_per_second}, +}; +use sp_runtime::traits::BadOrigin; +use xcm::{ + latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId, WeightLimit}, + VersionedMultiLocation, +}; +use xcm_emulator::TestExt; + +use crate::liquidity_pools::pallet::{ + development::{ + setup::{centrifuge_account, cfg, moonbeam_account, ALICE, BOB, CHARLIE, PARA_ID_MOONBEAM}, + test_net::{Development, Moonbeam, RelayChain, TestNet}, + tests::register_ausd, + }, + xcm_metadata, +}; + +/* + +NOTE: We hardcode the expected balances after an XCM operation given that the weights involved in +XCM execution often change slightly with each Polkadot update. We could simply test that the final +balance after some XCM operation is `initialBalance - amount - fee`, which would mean we would +never have to touch the tests again. However, by hard-coding these values we are forced to catch +an unexpectedly big change that would have a big impact on the weights and fees and thus balances, +which would go unnoticed and untreated otherwise. + + */ + +#[test] +fn transfer_cfg_to_sibling() { + TestNet::reset(); + + let alice_initial_balance = cfg(10_000); + let bob_initial_balance = cfg(10_000); + let transfer_amount = cfg(5); + let cfg_in_sibling = CurrencyId::ForeignAsset(12); + + // CFG Metadata + let meta: AssetMetadata = AssetMetadata { + decimals: 18, + name: "Development".into(), + symbol: "CFG".into(), + existential_deposit: 1_000_000_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::new( + 1, + X2( + Parachain(parachains::polkadot::centrifuge::ID), + general_key(parachains::polkadot::centrifuge::CFG_KEY), + ), + ))), + additional: CustomMetadata { + transferability: CrossChainTransferability::Xcm(Default::default()), + ..CustomMetadata::default() + }, + }; + + Development::execute_with(|| { + assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); + assert_eq!(Balances::free_balance(&moonbeam_account()), 0); + + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + meta.clone(), + Some(CurrencyId::Native), + )); + }); + + Moonbeam::execute_with(|| { + assert_eq!(OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()), 0); + + assert_ok!(OrmlAssetRegistry::register_asset( + RuntimeOrigin::root(), + meta, + Some(cfg_in_sibling) + )); + }); + + Development::execute_with(|| { + assert_ok!(XTokens::transfer( + RuntimeOrigin::signed(ALICE.into()), + CurrencyId::Native, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(PARA_ID_MOONBEAM), + Junction::AccountId32 { + network: None, + id: BOB, + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + // Confirm that Alice's balance is initial balance - amount transferred + assert_eq!( + Balances::free_balance(&ALICE.into()), + alice_initial_balance - transfer_amount + ); + + // Verify that the amount transferred is now part of the sibling account here + assert_eq!(Balances::free_balance(&moonbeam_account()), transfer_amount); + }); + + Moonbeam::execute_with(|| { + let current_balance = OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()); + + // Verify that BOB now has (amount transferred - fee) + assert_eq!(current_balance, transfer_amount - fee(18)); + + // Sanity check for the actual amount BOB ends up with + assert_eq!(current_balance, 4991987200000000000); + }); +} + +#[test] +fn transfer_cfg_sibling_to_centrifuge() { + TestNet::reset(); + + // In order to be able to transfer CFG from Moonbeam to Development, we need to + // first send CFG from Development to Moonbeam, or else it fails since it'd be + // like Moonbeam had minted CFG on their side. + transfer_cfg_to_sibling(); + + let alice_initial_balance = 9995000000000000000000; + let bob_initial_balance = cfg(5) - cfg_fee(); + let transfer_amount = cfg(4); + // Note: This asset was registered in `transfer_cfg_to_sibling` + let cfg_in_sibling = CurrencyId::ForeignAsset(12); + + Development::execute_with(|| { + assert_eq!(Balances::free_balance(&ALICE.into()), alice_initial_balance); + }); + + Moonbeam::execute_with(|| { + assert_eq!(Balances::free_balance(¢rifuge_account()), 0); + assert_eq!( + OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()), + bob_initial_balance + ); + + assert_ok!(XTokens::transfer( + RuntimeOrigin::signed(BOB.into()), + cfg_in_sibling, + transfer_amount, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(parachains::polkadot::centrifuge::ID), + Junction::AccountId32 { + network: None, + id: CHARLIE, + } + ) + ) + .into() + ), + WeightLimit::Limited(8_000_000_000_000.into()), + )); + + // Confirm that Charlie's balance is initial balance - amount transferred + assert_eq!( + OrmlTokens::free_balance(cfg_in_sibling, &BOB.into()), + bob_initial_balance - transfer_amount + ); + }); + + Development::execute_with(|| { + // Verify that Charlie's balance equals the amount transferred - fee + assert_eq!( + Balances::free_balance(&CHARLIE.into()), + transfer_amount - cfg_fee(), + ); + }); +} + +#[test] +fn test_total_fee() { + assert_eq!(cfg_fee(), 8012800000000000); +} + +fn cfg_fee() -> Balance { + fee(currency_decimals::NATIVE) +} + +fn ausd_fee() -> Balance { + fee(currency_decimals::AUSD) +} + +fn fee(decimals: u32) -> Balance { + calc_fee(default_per_second(decimals)) +} + +// The fee associated with transferring DOT tokens +fn dot_fee() -> Balance { + fee(10) +} + +fn calc_fee(fee_per_second: Balance) -> Balance { + // We divide the fee to align its unit and multiply by 4 as that seems to be the + // unit of time the tests take. + // NOTE: it is possible that in different machines this value may differ. We + // shall see. + fee_per_second.div_euclid(10_000) * 8 +} diff --git a/runtime/integration-tests/src/utils/evm.rs b/runtime/integration-tests/src/utils/evm.rs index 53520ce156..57bccefb0d 100644 --- a/runtime/integration-tests/src/utils/evm.rs +++ b/runtime/integration-tests/src/utils/evm.rs @@ -29,7 +29,7 @@ pub fn mint_balance_into_derived_account(env: &mut TestEnv, address: H160, balan .unwrap(); let derived_account = - AccountConverter::::convert_evm_address(chain_id, address.to_fixed_bytes()); + AccountConverter::::convert_evm_address(chain_id, address.to_fixed_bytes()); env.with_mut_state(Chain::Para(PARA_ID), || { Balances::mint_into(&derived_account.into(), balance).unwrap() @@ -45,7 +45,7 @@ pub fn deploy_contract(env: &mut TestEnv, address: H160, code: Vec) { .unwrap(); let derived_address = - AccountConverter::::convert_evm_address(chain_id, address.to_fixed_bytes()); + AccountConverter::::convert_evm_address(chain_id, address.to_fixed_bytes()); let transaction_create_cost = env .with_state(Chain::Para(PARA_ID), || { diff --git a/src/chain_spec.rs b/src/chain_spec.rs index f01888a814..94e79f9af9 100644 --- a/src/chain_spec.rs +++ b/src/chain_spec.rs @@ -23,7 +23,9 @@ #![allow(clippy::derive_partial_eq_without_eq)] use altair_runtime::constants::currency::{AIR, MILLI_AIR}; -use cfg_primitives::{currency_decimals, parachains, Balance, BlockNumber, CFG, MILLI_CFG}; +use cfg_primitives::{ + currency_decimals, parachains, Balance, BlockNumber, CFG, MILLI_CFG, SAFE_XCM_VERSION, +}; use cfg_types::{ fee_keys::FeeKey, tokens::{ @@ -552,7 +554,7 @@ fn centrifuge_genesis( endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| { let chain_id = id.unwrap_or_else(|| chain_id.into()); - AccountConverter::::convert_evm_address(chain_id, addr) + AccountConverter::::convert_evm_address(chain_id, addr) })); let num_endowed_accounts = endowed_accounts.len(); @@ -658,11 +660,15 @@ fn centrifuge_genesis( }, block_rewards_base: Default::default(), base_fee: Default::default(), - evm_chain_id: development_runtime::EVMChainIdConfig { + evm_chain_id: centrifuge_runtime::EVMChainIdConfig { chain_id: chain_id.into(), }, ethereum: Default::default(), evm: Default::default(), + liquidity_rewards_base: Default::default(), + polkadot_xcm: centrifuge_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, } } @@ -678,7 +684,7 @@ fn altair_genesis( endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| { let chain_id = id.unwrap_or_else(|| chain_id.into()); - AccountConverter::::convert_evm_address(chain_id, addr) + AccountConverter::::convert_evm_address(chain_id, addr) })); let num_endowed_accounts = endowed_accounts.len(); @@ -766,12 +772,15 @@ fn altair_genesis( parachain_system: Default::default(), treasury: Default::default(), base_fee: Default::default(), - evm_chain_id: development_runtime::EVMChainIdConfig { + evm_chain_id: altair_runtime::EVMChainIdConfig { chain_id: chain_id.into(), }, ethereum: Default::default(), evm: Default::default(), liquidity_rewards_base: Default::default(), + polkadot_xcm: altair_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, } } @@ -791,7 +800,7 @@ fn development_genesis( endowed_accounts.extend(endowed_evm_accounts.into_iter().map(|(addr, id)| { let chain_id = id.unwrap_or_else(|| chain_id.into()); - AccountConverter::::convert_evm_address(chain_id, addr) + AccountConverter::::convert_evm_address(chain_id, addr) })); let num_endowed_accounts = endowed_accounts.len(); @@ -931,6 +940,9 @@ fn development_genesis( evm: Default::default(), block_rewards_base: Default::default(), liquidity_rewards_base: Default::default(), + polkadot_xcm: development_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, } } From c203b4f1a14c77ea5fdb16dd4176ec3fa3309e05 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 16:06:57 +0200 Subject: [PATCH 83/96] feat: add orderbook + fi to cfg runtime --- Cargo.lock | 2 + runtime/centrifuge/Cargo.toml | 12 +- runtime/centrifuge/src/lib.rs | 63 +++++++- runtime/centrifuge/src/weights/mod.rs | 1 + .../src/weights/pallet_order_book.rs | 143 ++++++++++++++++++ 5 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 runtime/centrifuge/src/weights/pallet_order_book.rs diff --git a/Cargo.lock b/Cargo.lock index 49cc67ef0f..ef7c47a2fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,6 +1195,7 @@ dependencies = [ "pallet-evm-chain-id", "pallet-evm-precompile-dispatch", "pallet-fees", + "pallet-foreign-investments", "pallet-identity", "pallet-interest-accrual", "pallet-investments", @@ -1207,6 +1208,7 @@ dependencies = [ "pallet-migration-manager", "pallet-multisig", "pallet-nft", + "pallet-order-book", "pallet-permissions", "pallet-pool-registry", "pallet-pool-system", diff --git a/runtime/centrifuge/Cargo.toml b/runtime/centrifuge/Cargo.toml index cb6a21f766..247076045e 100644 --- a/runtime/centrifuge/Cargo.toml +++ b/runtime/centrifuge/Cargo.toml @@ -116,7 +116,7 @@ pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-fea pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } -# pallet-foreign-investments = { path = "../../pallets/foreign-investments", default-features = false } +pallet-foreign-investments = { path = "../../pallets/foreign-investments", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } pallet-keystore = { path = "../../pallets/keystore", default-features = false } @@ -126,6 +126,7 @@ pallet-liquidity-rewards = { path = "../../pallets/liquidity-rewards", default-f pallet-loans = { path = "../../pallets/loans", default-features = false } pallet-migration-manager = { path = "../../pallets/migration", default-features = false } pallet-nft = { path = "../../pallets/nft", default-features = false } +pallet-order-book = { path = "../../pallets/order-book", default-features = false } pallet-permissions = { path = "../../pallets/permissions", default-features = false } pallet-pool-registry = { path = "../../pallets/pool-registry", default-features = false } pallet-pool-system = { path = "../../pallets/pool-system", default-features = false } @@ -202,7 +203,7 @@ std = [ "pallet-evm-precompile-dispatch/std", "pallet-evm-chain-id/std", "pallet-fees/std", - # "pallet-foreign-investments/std", + "pallet-foreign-investments/std", "pallet-identity/std", "pallet-interest-accrual/std", "pallet-investments/std", @@ -215,6 +216,7 @@ std = [ "pallet-multisig/std", "pallet-membership/std", "pallet-nft/std", + "pallet-order-book/std", "pallet-permissions/std", "pallet-pool-registry/std", "pallet-pool-system/std", @@ -291,7 +293,7 @@ runtime-benchmarks = [ "pallet-ethereum-transaction/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", - # "pallet-foreign-investments/runtime-benchmarks", + "pallet-foreign-investments/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-interest-accrual/runtime-benchmarks", "pallet-investments/runtime-benchmarks", @@ -304,6 +306,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-nft/runtime-benchmarks", + "pallet-order-book/runtime-benchmarks", "pallet-permissions/runtime-benchmarks", "pallet-pool-registry/runtime-benchmarks", "pallet-pool-system/runtime-benchmarks", @@ -372,7 +375,7 @@ try-runtime = [ "pallet-evm/try-runtime", "pallet-evm-chain-id/try-runtime", "pallet-fees/try-runtime", - # "pallet-foreign-investments/try-runtime", + "pallet-foreign-investments/try-runtime", "pallet-identity/try-runtime", "pallet-interest-accrual/try-runtime", "pallet-investments/try-runtime", @@ -385,6 +388,7 @@ try-runtime = [ "pallet-multisig/try-runtime", "pallet-membership/try-runtime", "pallet-nft/try-runtime", + "pallet-order-book/try-runtime", "pallet-permissions/try-runtime", "pallet-pool-registry/try-runtime", "pallet-pool-system/try-runtime", diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index a6a95dd28d..c15b9bcbee 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -91,7 +91,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, - Dispatchable, PostDispatchInfoOf, UniqueSaturatedInto, Zero, + Dispatchable, One, PostDispatchInfoOf, UniqueSaturatedInto, Zero, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, FixedI128, Perbill, Permill, Perquintill, @@ -429,6 +429,36 @@ impl orml_asset_registry::Config for Runtime { type WeightInfo = (); } +parameter_types! { + pub DefaultTokenSellRate: Rate = Rate::one(); + pub StableToStableRate: Rate = Rate::one(); +} + +impl pallet_foreign_investments::Config for Runtime { + type Balance = Balance; + type CollectedForeignRedemptionHook = + pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; + type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< + OrmlAssetRegistry, + StableToStableRate, + >; + type CurrencyId = CurrencyId; + type DecreasedForeignInvestOrderHook = + pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; + type DefaultTokenSellRate = DefaultTokenSellRate; + type Investment = Investments; + type InvestmentId = TrancheCurrency; + type PoolId = PoolId; + type PoolInspect = PoolSystem; + // TODO: Switch to ratio after merging #1546 + type Rate = Rate; + type RuntimeEvent = RuntimeEvent; + type TokenSwapOrderId = u64; + type TokenSwaps = OrderBook; + type TrancheId = TrancheId; + type WeightInfo = (); +} + parameter_types! { // To be used if we want to register a particular asset in the chain spec, when running the chain locally. pub LiquidityPoolsPalletIndex: PalletIndex = ::index() as u8; @@ -442,7 +472,7 @@ impl pallet_liquidity_pools::Config for Runtime { type CurrencyId = CurrencyId; type DomainAccountToAccountId = AccountConverter; type DomainAddressToAccountId = AccountConverter; - type ForeignInvestment = Investments; + type ForeignInvestment = ForeignInvestments; type GeneralCurrencyPrefix = cfg_primitives::liquidity_pools::GeneralCurrencyPrefix; type OutboundQueue = FilteredOutboundQueue; type Permission = Permissions; @@ -1758,8 +1788,11 @@ impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; type BalanceRatio = Quantity; - type CollectedInvestmentHook = NoopCollectHook; - type CollectedRedemptionHook = NoopCollectHook; + type CollectedInvestmentHook = + pallet_foreign_investments::hooks::CollectedInvestmentHook; + type CollectedRedemptionHook = + pallet_foreign_investments::hooks::CollectedRedemptionHook; + type InvestmentId = TrancheCurrency; type MaxOutstandingCollects = MaxOutstandingCollects; type PreConditions = IsTrancheInvestor; type RuntimeEvent = RuntimeEvent; @@ -1919,6 +1952,24 @@ impl pallet_uniques::Config for Runtime { type WeightInfo = weights::pallet_uniques::WeightInfo; } +parameter_types! { + pub const OrderPairVecSize: u32 = 1_000u32; +} + +impl pallet_order_book::Config for Runtime { + type AdminOrigin = EnsureRoot; + type AssetCurrencyId = CurrencyId; + type AssetRegistry = OrmlAssetRegistry; + type Balance = Balance; + type FulfilledOrderHook = pallet_foreign_investments::hooks::FulfilledSwapOrderHook; + type OrderIdNonce = u64; + type OrderPairVecSize = OrderPairVecSize; + type RuntimeEvent = RuntimeEvent; + type SellRatio = Rate; + type TradeableAsset = Tokens; + type Weights = weights::pallet_order_book::WeightInfo; +} + // Frame Order in this block dictates the index of each one in the metadata // Any addition should be done at the bottom // Any deletion affects the following frames during runtime upgrades @@ -1979,6 +2030,8 @@ construct_runtime!( LiquidityRewards: pallet_liquidity_rewards::{Pallet, Call, Storage, Event} = 105, GapRewardMechanism: pallet_rewards::mechanism::gap = 106, LiquidityPoolsGateway: pallet_liquidity_pools_gateway::{Pallet, Call, Storage, Event, Origin } = 107, + OrderBook: pallet_order_book::{Pallet, Call, Storage, Event} = 108, + ForeignInvestments: pallet_foreign_investments::{Pallet, Storage, Event} = 109, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, @@ -2498,6 +2551,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_loans, Loans); list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); list_benchmark!(list, extra, cumulus_pallet_xcmp_queue, XcmpQueue); + list_benchmark!(list, extra, pallet_order_book, OrderBook); let storage_info = AllPalletsWithSystem::storage_info(); @@ -2568,6 +2622,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_loans, Loans); add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); add_benchmark!(params, batches, cumulus_pallet_xcmp_queue, XcmpQueue); + add_benchmark!(params, batches, pallet_order_book, OrderBook); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/centrifuge/src/weights/mod.rs b/runtime/centrifuge/src/weights/mod.rs index 12100a50dc..e3a5d11f4a 100644 --- a/runtime/centrifuge/src/weights/mod.rs +++ b/runtime/centrifuge/src/weights/mod.rs @@ -29,6 +29,7 @@ pub mod pallet_liquidity_rewards; pub mod pallet_loans; pub mod pallet_migration_manager; pub mod pallet_multisig; +pub mod pallet_order_book; pub mod pallet_permissions; pub mod pallet_pool_registry; pub mod pallet_pool_system; diff --git a/runtime/centrifuge/src/weights/pallet_order_book.rs b/runtime/centrifuge/src/weights/pallet_order_book.rs new file mode 100644 index 0000000000..a4ef7881a2 --- /dev/null +++ b/runtime/centrifuge/src/weights/pallet_order_book.rs @@ -0,0 +1,143 @@ + +//! Autogenerated weights for `pallet_order_book` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-29, STEPS: `10`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `kf-FG`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("development-local"), DB CACHE: 1024 + +// Executed Command: +// target/release/centrifuge-chain +// benchmark +// pallet +// --chain=development-local +// --steps=10 +// --repeat=1 +// --pallet=pallet-order-book +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=pallet-order-book.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_order_book`. +pub struct WeightInfo(PhantomData); +impl pallet_order_book::WeightInfo for WeightInfo { + /// Storage: OrderBook OrderIdNonceStore (r:1 w:1) + /// Proof: OrderBook OrderIdNonceStore (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: OrderBook TradingPair (r:1 w:0) + /// Proof: OrderBook TradingPair (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Storage: OrderBook Orders (r:0 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn create_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1217` + // Estimated: `8014376` + // Minimum execution time: 46_000 nanoseconds. + Weight::from_parts(46_000_000, 8014376) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrderBook TradingPair (r:1 w:0) + /// Proof: OrderBook TradingPair (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: OrmlAssetRegistry Metadata (r:2 w:0) + /// Proof Skipped: OrmlAssetRegistry Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:1 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn user_update_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1722` + // Estimated: `17195` + // Minimum execution time: 40_000 nanoseconds. + Weight::from_parts(40_000_000, 17195) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:1 w:1) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn user_cancel_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `1116` + // Estimated: `8007810` + // Minimum execution time: 32_000 nanoseconds. + Weight::from_parts(32_000_000, 8007810) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: OrderBook Orders (r:1 w:1) + /// Proof: OrderBook Orders (max_values: None, max_size: Some(186), added: 2661, mode: MaxEncodedLen) + /// Storage: OrmlTokens Accounts (r:4 w:4) + /// Proof: OrmlTokens Accounts (max_values: None, max_size: Some(129), added: 2604, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: OrderBook AssetPairOrders (r:1 w:1) + /// Proof: OrderBook AssetPairOrders (max_values: None, max_size: Some(8000070), added: 8002545, mode: MaxEncodedLen) + /// Storage: OrderBook UserOrders (r:0 w:1) + /// Proof: OrderBook UserOrders (max_values: None, max_size: Some(226), added: 2701, mode: MaxEncodedLen) + fn fill_order_full() -> Weight { + // Proof Size summary in bytes: + // Measured: `1702` + // Estimated: `8020828` + // Minimum execution time: 64_000 nanoseconds. + Weight::from_parts(64_000_000, 8020828) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: OrderBook TradingPair (r:0 w:1) + /// Proof: OrderBook TradingPair (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + fn add_trading_pair() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_000 nanoseconds. + Weight::from_ref_time(9_000_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: OrderBook TradingPair (r:0 w:1) + /// Proof: OrderBook TradingPair (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + fn rm_trading_pair() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_000 nanoseconds. + Weight::from_ref_time(9_000_000) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: OrderBook TradingPair (r:1 w:1) + /// Proof: OrderBook TradingPair (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + fn update_min_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `209` + // Estimated: `2557` + // Minimum execution time: 14_000 nanoseconds. + Weight::from_parts(14_000_000, 2557) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} From c91f17dc55ce7b349db27ef7959ce0699593102a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 16:07:08 +0200 Subject: [PATCH 84/96] tests: fix LP messages --- pallets/liquidity-pools/src/message.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 1620f8384a..94d863f419 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -1244,7 +1244,7 @@ mod tests { currency_payout: AMOUNT / 2, remaining_invest_amount: AMOUNT / 4, }, - "0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", + "0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000000000000014adf4b7320334b9000000", ) } @@ -1259,7 +1259,7 @@ mod tests { tranche_tokens_payout: AMOUNT / 2, remaining_redeem_amount: AMOUNT / 4, }, - "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000", + "100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000000000000014adf4b7320334b9000000", ) } @@ -1275,7 +1275,7 @@ mod tests { tranche_tokens_payout: AMOUNT / 2, remaining_invest_amount: AMOUNT / 4, }, - "110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", + "110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000000000000014adf4b7320334b9000000", ) } @@ -1291,7 +1291,7 @@ mod tests { tranche_tokens_payout: AMOUNT / 2, remaining_redeem_amount: AMOUNT / 4, }, - "120000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000", + "120000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000000000000014adf4b7320334b9000000", ) } From 5d4de16bc9ba1aa41bd630cc08d116af478d1d73 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 17:13:41 +0200 Subject: [PATCH 85/96] fix: integration tests --- pallets/liquidity-pools/src/inbound.rs | 2 +- .../liquidity_pools/add_allow_upgrade.rs | 41 +++---------------- .../liquidity_pools/foreign_investments.rs | 8 ++-- .../tests/liquidity_pools/setup.rs | 7 ++-- .../tests/liquidity_pools/transfers.rs | 6 +-- .../pallet/development/tests/mod.rs | 2 +- 6 files changed, 20 insertions(+), 46 deletions(-) diff --git a/pallets/liquidity-pools/src/inbound.rs b/pallets/liquidity-pools/src/inbound.rs index 555cd5dbdb..68d24cbc15 100644 --- a/pallets/liquidity-pools/src/inbound.rs +++ b/pallets/liquidity-pools/src/inbound.rs @@ -195,7 +195,7 @@ where // Transfer tranche tokens from `DomainLocator` account of // origination domain - // TODO(@review): Should this rather be pat of `increase_foreign_redemption`? + // TODO(@review): Should this rather be part of `increase_foreign_redemption`? T::Tokens::transfer( invest_id.clone().into(), &Domain::convert(sending_domain.domain()), diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs index ec38b159be..656fd5de9e 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/add_allow_upgrade.rs @@ -37,8 +37,8 @@ use cfg_types::{ }, }; use development_runtime::{ - LiquidityPools, OrmlAssetRegistry, OrmlTokens, Permissions, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, TreasuryAccount, XTokens, XcmTransactor, + LiquidityPools, LocationToAccountId, OrmlAssetRegistry, OrmlTokens, Permissions, + Runtime as DevelopmentRuntime, RuntimeOrigin, System, TreasuryAccount, XTokens, XcmTransactor, }; use frame_support::{assert_noop, assert_ok, traits::fungibles::Mutate}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; @@ -299,7 +299,7 @@ fn add_currency() { assert_eq!( OrmlTokens::free_balance( - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, &::Sender::get() ), DEFAULT_BALANCE_GLMR @@ -312,7 +312,7 @@ fn add_currency() { assert_eq!( OrmlTokens::free_balance( - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, &::Sender::get() ), /// Ensure it only charged the 0.2 GLMR of fee @@ -647,13 +647,6 @@ fn schedule_upgrade() { BadOrigin ); - // Need to burn default minted balance from Treasury - OrmlTokens::burn_from( - GLMR_CURRENCY_ID, - &TreasuryAccount::get(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); - // Now it finally works assert_ok!(LiquidityPools::schedule_upgrade( RuntimeOrigin::root(), @@ -669,7 +662,7 @@ fn cancel_upgrade_upgrade() { Development::execute_with(|| { setup_pre_requirements(); - // Only Root can call `schedule_upgrade` + // Only Root can call `cancel_upgrade` assert_noop!( LiquidityPools::cancel_upgrade( RuntimeOrigin::signed(BOB.into()), @@ -679,29 +672,7 @@ fn cancel_upgrade_upgrade() { BadOrigin ); - // Need to burn default minted balance from Treasury - OrmlTokens::burn_from( - GLMR_CURRENCY_ID, - &TreasuryAccount::get(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); - - // Failing because the treasury has no funds - assert_noop!( - LiquidityPools::cancel_upgrade(RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, [7; 20]), - pallet_xcm_transactor::Error::::UnableToWithdrawAsset - ); - - // The treasury needs GLRM to cover the fees of sending - // this message - OrmlTokens::deposit( - GLMR_CURRENCY_ID, - &TreasuryAccount::get(), - DEFAULT_BALANCE_GLMR * dollar(18), - ); - - // Now it finally works (even though nothing was scheduled which we don't check - // on the local domain) + // Now it finally works assert_ok!(LiquidityPools::cancel_upgrade( RuntimeOrigin::root(), MOONBEAM_EVM_CHAIN_ID, diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 493965b9a4..1f7554f347 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -30,7 +30,7 @@ use cfg_traits::{ }; use cfg_types::{ domain_address::{Domain, DomainAddress}, - fixed_point::Rate, + fixed_point::{Quantity, Rate}, investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection, Swap}, orders::FulfillmentWithPrice, permissions::{PermissionScope, PoolRole, Role, UNION}, @@ -41,8 +41,9 @@ use cfg_types::{ }, }; use development_runtime::{ - Balances, ForeignInvestments, Investments, LiquidityPools, OrmlAssetRegistry, Permissions, - PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, StableToStableRate, System, Tokens, + Balances, ForeignInvestments, Investments, LiquidityPools, LocationToAccountId, + OrmlAssetRegistry, Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, + StableToStableRate, System, Tokens, }; use frame_support::{ assert_noop, assert_ok, @@ -90,6 +91,7 @@ use crate::{ }; mod same_currencies { + use pallet_foreign_investments::{CollectedInvestment, InvestmentState}; use super::*; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs index 3bb24f4c5b..664abe3a41 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/setup.rs @@ -26,7 +26,7 @@ use cfg_primitives::{currency_decimals, Balance, Moment, PoolId, TrancheId}; use cfg_traits::{investments::InvestmentAccountant, PoolMutate}; use cfg_types::{ domain_address::{Domain, DomainAddress}, - fixed_point::Rate, + fixed_point::{Quantity, Rate}, pools::TrancheMetadata, tokens::{CrossChainTransferability, CurrencyId, CustomMetadata}, }; @@ -45,7 +45,7 @@ use frame_support::{ }; use liquidity_pools_gateway_routers::{ ethereum_xcm::EthereumXCMRouter, DomainRouter, XCMRouter, XcmDomain as GatewayXcmDomain, - XcmTransactInfo, + XcmTransactInfo, DEFAULT_PROOF_SIZE, }; use orml_asset_registry::{AssetMetadata, Metadata}; use pallet_liquidity_pools::Message; @@ -86,6 +86,7 @@ pub const DEFAULT_MOONBEAM_LOCATION: MultiLocation = MultiLocation { parents: 1, interior: X1(Parachain(PARA_ID_MOONBEAM)), }; +use frame_support::weights::Weight; pub type LiquidityPoolMessage = Message; @@ -168,7 +169,7 @@ pub fn setup_pre_requirements() { // Fund the gateway sender account with enough glimmer to pay for fees OrmlTokens::deposit( - GLIMMER_CURRENCY_ID, + GLMR_CURRENCY_ID, &::Sender::get(), DEFAULT_BALANCE_GLMR, ); diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs index 0b537b15bf..a4c9080b78 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/transfers.rs @@ -37,10 +37,10 @@ use cfg_types::{ }, }; use development_runtime::{ - LiquidityPools, OrmlTokens, Permissions, PoolSystem, Runtime as DevelopmentRuntime, - RuntimeOrigin, System, + LiquidityPools, LocationToAccountId, OrmlTokens, Permissions, PoolSystem, + Runtime as DevelopmentRuntime, RuntimeOrigin, System, }; -use frame_support::{assert_noop, assert_ok, traits::fungibles::Mutate}; +use frame_support::{assert_noop, assert_ok, dispatch::Weight, traits::fungibles::Mutate}; use orml_traits::{asset_registry::AssetMetadata, FixedConversionRateProvider, MultiCurrency}; use runtime_common::account_conversion::AccountConverter; use sp_runtime::{ diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs index 88fb0b1946..7ac3eef92a 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/mod.rs @@ -16,7 +16,7 @@ mod liquidity_pools; mod routers; /// Register AUSD in the asset registry. -/// +/// /// NOTE: It should be executed within an externalities environment. pub fn register_ausd() { let meta: AssetMetadata = AssetMetadata { From d09ca6d4551c482e72571a1a97d74e369d28f418 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 12 Sep 2023 17:18:11 +0200 Subject: [PATCH 86/96] docs: add missing --- pallets/foreign-investments/src/hooks.rs | 6 ++++++ pallets/foreign-investments/src/impls/invest.rs | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index ec203687e5..08e5e6fcea 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -101,6 +101,11 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { } impl FulfilledSwapOrderHook { + /// Transitions the `InvestState` after fulfilling a swap order. + /// + /// NOTE: If the transition should be followed by a `RedeemState` + /// transition, the `update_swap_order` should be set to false in order to + /// oppress updating the swap order here. fn fulfill_invest_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, @@ -136,6 +141,7 @@ impl FulfilledSwapOrderHook { ) } + /// Transitions the `RedeemState` after fulfilling a swap order. fn fulfill_redeem_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 3e74f63dcd..156de031a6 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -51,7 +51,8 @@ where } } - // TODO: Docs + /// Returns the active swap if it exists, i.e. if the state includes + /// `ActiveSwapInto{Foreign, Pool}Currency`. pub(crate) fn get_active_swap(&self) -> Option> { match *self { Self::NoState => None, From 53039e50e51adb52434417b928a3ece3faf38bc4 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 13 Sep 2023 10:08:21 +0200 Subject: [PATCH 87/96] Merge remote-tracking branch 'origin/main' into feat/wf-foreign-investments --- Cargo.lock | 6 +- .../axelar-gateway-precompile/Cargo.toml | 1 + .../axelar-gateway-precompile/src/lib.rs | 212 +++++++--------- .../routers/Cargo.toml | 1 + .../routers/src/routers/axelar_evm.rs | 11 +- pallets/order-book/src/benchmarking.rs | 17 +- pallets/order-book/src/mock.rs | 3 +- pallets/order-book/src/tests.rs | 114 ++++----- runtime/altair/src/lib.rs | 20 +- runtime/centrifuge/src/lib.rs | 23 +- runtime/common/src/account_conversion.rs | 1 + runtime/common/src/evm/precompile.rs | 2 +- runtime/common/src/lib.rs | 14 +- runtime/development/Cargo.toml | 2 +- runtime/development/src/lib.rs | 23 +- runtime/integration-tests/Cargo.toml | 3 + .../pallet.rs => evm/ethereum_transaction.rs} | 1 - .../src/{ethereum_transaction => evm}/mod.rs | 3 +- .../integration-tests/src/evm/precompile.rs | 232 ++++++++++++++++++ runtime/integration-tests/src/lib.rs | 2 +- .../liquidity_pools/foreign_investments.rs | 30 +-- 21 files changed, 464 insertions(+), 257 deletions(-) rename runtime/integration-tests/src/{ethereum_transaction/pallet.rs => evm/ethereum_transaction.rs} (99%) rename runtime/integration-tests/src/{ethereum_transaction => evm}/mod.rs (93%) create mode 100644 runtime/integration-tests/src/evm/precompile.rs diff --git a/Cargo.lock b/Cargo.lock index ef7c47a2fc..77d3db9017 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -612,6 +612,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "hex", "pallet-evm", "pallet-liquidity-pools-gateway", "parity-scale-codec 3.6.4", @@ -2685,7 +2686,7 @@ dependencies = [ [[package]] name = "development-runtime" -version = "0.10.21" +version = "0.10.23" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", @@ -5810,6 +5811,7 @@ dependencies = [ "ethabi 16.0.0", "frame-support", "frame-system", + "hex", "lazy_static", "orml-traits", "pallet-balances", @@ -11048,6 +11050,7 @@ name = "runtime-integration-tests" version = "0.1.0" dependencies = [ "altair-runtime", + "axelar-gateway-precompile", "centrifuge-runtime", "cfg-primitives", "cfg-traits", @@ -11055,6 +11058,7 @@ dependencies = [ "cfg-utils", "cumulus-primitives-core", "development-runtime", + "ethabi 16.0.0", "ethereum", "frame-benchmarking", "frame-support", diff --git a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml index 63a59815c0..52dacaed9b 100644 --- a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml +++ b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +hex = { version = "0.4.3", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } diff --git a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs index 2a272a754b..7fe1ceea51 100644 --- a/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs +++ b/pallets/liquidity-pools-gateway/axelar-gateway-precompile/src/lib.rs @@ -12,20 +12,22 @@ #![cfg_attr(not(feature = "std"), no_std)] use cfg_types::domain_address::{Domain, DomainAddress}; -use codec::alloc::string::ToString; -use ethabi::Token; use fp_evm::PrecompileHandle; -use frame_support::{Blake2_256, StorageHasher}; +use frame_support::ensure; use pallet_evm::{ExitError, PrecompileFailure}; use precompile_utils::prelude::*; -use sp_core::{bounded::BoundedVec, ConstU32, H160, H256, U256}; -use sp_runtime::{DispatchError, DispatchResult}; +use sp_core::{bounded::BoundedVec, ConstU32, H256, U256}; +use sp_runtime::{ + traits::{BlakeTwo256, Hash}, + DispatchError, +}; use sp_std::vec::Vec; pub use crate::weights::WeightInfo; pub const MAX_SOURCE_CHAIN_BYTES: u32 = 128; -pub const MAX_SOURCE_ADDRESS_BYTES: u32 = 32; +// Ensure we allow enough to support a hex encoded address with the `0x` prefix. +pub const MAX_SOURCE_ADDRESS_BYTES: u32 = 42; pub const MAX_TOKEN_SYMBOL_BYTES: u32 = 32; pub const MAX_PAYLOAD_BYTES: u32 = 1024; pub const PREFIX_CONTRACT_CALL_APPROVED: [u8; 32] = keccak256!("contract-call-approved"); @@ -47,7 +49,7 @@ pub mod weights; frame_support::RuntimeDebugNoBound, )] pub struct SourceConverter { - domain: Domain, + pub domain: Domain, } impl SourceConverter { @@ -116,7 +118,7 @@ pub mod pallet { } #[pallet::storage] - pub type AxelarGatewayContract = StorageValue<_, H160, ValueQuery>; + pub type GatewayContract = StorageValue<_, H160, ValueQuery>; /// `SourceConversion` is a `hash_of(Vec)` where the `Vec` is the /// blake256-hash of the source-chain identifier used by the Axelar network. @@ -142,7 +144,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - AxelarGatewayContract::::set(self.gateway) + GatewayContract::::set(self.gateway) } } @@ -174,7 +176,7 @@ pub mod pallet { pub fn set_gateway(origin: OriginFor, address: H160) -> DispatchResult { ::AdminOrigin::ensure_origin(origin)?; - AxelarGatewayContract::::set(address); + GatewayContract::::set(address); Self::deposit_event(Event::::GatewaySet { address }); @@ -205,9 +207,8 @@ impl cfg_traits::TryConvert<(Vec, Vec), DomainAddress> for Pa fn try_convert(origin: (Vec, Vec)) -> Result { let (source_chain, source_address) = origin; - let domain_converter = - SourceConversion::::get(H256::from(Blake2_256::hash(&source_chain))) - .ok_or(Error::::NoConverterForSource)?; + let domain_converter = SourceConversion::::get(BlakeTwo256::hash(&source_chain)) + .ok_or(Error::::NoConverterForSource)?; domain_converter .try_convert(&source_address) @@ -246,30 +247,17 @@ where #[precompile::public("execute(bytes32,string,string,bytes)")] fn execute( handle: &mut impl PrecompileHandle, - command_id: H256, + _command_id: H256, source_chain: String, source_address: String, payload: Bytes, ) -> EvmResult { - // CREATE HASH OF PAYLOAD - // - bytes32 payloadHash = keccak256(payload); - let payload_hash = H256::from(sp_io::hashing::keccak_256(payload.as_bytes())); - - // CHECK EVM STORAGE OF GATEWAY - // - keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, - // sourceAddress, contractAddress, payloadHash)); - let key = H256::from(sp_io::hashing::keccak_256(ðabi::encode(&[ - Token::FixedBytes(PREFIX_CONTRACT_CALL_APPROVED.into()), - Token::FixedBytes(command_id.as_bytes().into()), - Token::String(source_chain.clone().try_into().map_err(|_| { - RevertReason::read_out_of_bounds("utf-8 encoding failing".to_string()) - })?), - Token::String(source_address.clone().try_into().map_err(|_| { - RevertReason::read_out_of_bounds("utf-8 encoding failing".to_string()) - })?), - Token::Address(handle.context().address), - Token::FixedBytes(payload_hash.as_bytes().into()), - ]))); + ensure!( + handle.context().caller == GatewayContract::::get(), + PrecompileFailure::Error { + exit_status: ExitError::Other("gateway contract address mismatch".into()), + } + ); let msg = BoundedVec::< u8, @@ -279,20 +267,34 @@ where exit_status: ExitError::Other("payload conversion".into()), })?; - Self::execute_call(key, || { - let domain_converter = - SourceConversion::::get(H256::from(Blake2_256::hash(source_chain.as_bytes()))) - .ok_or(Error::::NoConverterForSource)?; + let domain_converter = SourceConversion::::get(BlakeTwo256::hash( + source_chain.as_bytes(), + )) + .ok_or(PrecompileFailure::Error { + exit_status: ExitError::Other("converter for source not found".into()), + })?; - let domain_address = domain_converter - .try_convert(source_address.as_bytes()) - .ok_or(Error::::AccountBytesMismatchForDomain)?; + let source_address_bytes = + get_source_address_bytes(source_address).ok_or(PrecompileFailure::Error { + exit_status: ExitError::Other("invalid source address".into()), + })?; - pallet_liquidity_pools_gateway::Pallet::::process_msg( - pallet_liquidity_pools_gateway::GatewayOrigin::Domain(domain_address).into(), - msg, - ) - }) + let domain_address = domain_converter + .try_convert(source_address_bytes.as_slice()) + .ok_or(PrecompileFailure::Error { + exit_status: ExitError::Other("account bytes mismatch for domain".into()), + })?; + + match pallet_liquidity_pools_gateway::Pallet::::process_msg( + pallet_liquidity_pools_gateway::GatewayOrigin::Domain(domain_address).into(), + msg, + ) + .map(|_| ()) + .map_err(TryDispatchError::Substrate) + { + Err(e) => Err(e.into()), + Ok(()) => Ok(()), + } } // Mimics: @@ -323,98 +325,56 @@ where // TODO: Check whether this is enough or if we should error out Ok(()) } +} - fn execute_call(key: H256, f: impl FnOnce() -> DispatchResult) -> EvmResult { - let gateway = AxelarGatewayContract::::get(); +const EXPECTED_SOURCE_ADDRESS_SIZE: usize = 20; +const HEX_PREFIX: &str = "0x"; - let valid = Self::get_validate_call(gateway, key); +pub(crate) fn get_source_address_bytes( + source_address: String, +) -> Option> { + if source_address.as_bytes().len() == EXPECTED_SOURCE_ADDRESS_SIZE { + return Some(source_address.as_bytes().to_vec()); + } - if valid { - // Prevent re-entrance - Self::set_validate_call(gateway, key, false); + let str = source_address.as_str().ok()?; - match f().map(|_| ()).map_err(TryDispatchError::Substrate) { - Err(e) => { - Self::set_validate_call(gateway, key, true); - Err(e.into()) - } - Ok(()) => Ok(()), - } - } else { - Err(RevertReason::Custom("Call not validated".to_string()).into()) + // Attempt to hex decode source address. + match hex::decode(str) { + Ok(res) => Some(res), + Err(_) => { + // Strip 0x prefix. + let res = str.strip_prefix(HEX_PREFIX)?; + + hex::decode(res).ok() } } +} - fn get_validate_call(from: H160, key: H256) -> bool { - Self::h256_to_bool(pallet_evm::AccountStorages::::get( - from, - Self::get_index_validate_call(key), - )) - } +#[cfg(test)] +mod tests { + use sp_core::H160; - fn set_validate_call(from: H160, key: H256, valid: bool) { - pallet_evm::AccountStorages::::set( - from, - Self::get_index_validate_call(key), - Self::bool_to_h256(valid), - ) - } + use super::*; - fn get_index_validate_call(key: H256) -> H256 { - // Generate right index: - // - // From the solidty contract of Axelar (EternalStorage.sol) - // mapping(bytes32 => uint256) private _uintStorage; -> Slot 0 - // mapping(bytes32 => string) private _stringStorage; -> Slot 1 - // mapping(bytes32 => address) private _addressStorage; -> Slot 2 - // mapping(bytes32 => bytes) private _bytesStorage; -> Slot 3 - // mapping(bytes32 => bool) private _boolStorage; -> Slot 4 - // mapping(bytes32 => int256) private _intStorage; -> Slot 5 - // - // This means our slot is U256::from(4) - let slot = U256::from(4); - - let mut bytes = Vec::new(); - bytes.extend_from_slice(key.as_bytes()); - - let mut be_bytes: [u8; 32] = [0u8; 32]; - // TODO: Is endnianess correct here? - slot.to_big_endian(&mut be_bytes); - bytes.extend_from_slice(&be_bytes); - - H256::from(sp_io::hashing::keccak_256(&bytes)) - } + #[test] + fn get_source_address_bytes_works() { + let hash = H160::from_low_u64_be(1); - // In Solidity, a boolean value (bool) is stored as a single byte (8 bits) in - // contract storage. The byte value 0x01 represents true, and the byte value - // 0x00 represents false. - // - // When you declare a boolean variable within a contract and store its value in - // storage, the contract reserves one storage slot, which is 32 bytes (256 bits) - // in size. However, only the first byte (8 bits) of that storage slot is used - // to store the boolean value. The remaining 31 bytes are left unused. - fn h256_to_bool(value: H256) -> bool { - let first = value.0[0]; - - // TODO; Should we check the other values too and error out then? - first == 1 - } + let str = String::::from(hash.as_fixed_bytes().to_vec()); - // In Solidity, a boolean value (bool) is stored as a single byte (8 bits) in - // contract storage. The byte value 0x01 represents true, and the byte value - // 0x00 represents false. - // - // When you declare a boolean variable within a contract and store its value in - // storage, the contract reserves one storage slot, which is 32 bytes (256 bits) - // in size. However, only the first byte (8 bits) of that storage slot is used - // to store the boolean value. The remaining 31 bytes are left unused. - fn bool_to_h256(value: bool) -> H256 { - let mut bytes: [u8; 32] = [0u8; 32]; - - if value { - bytes[0] = 1; - } + get_source_address_bytes(str).expect("address bytes from H160 works"); + + let str = String::::from( + "d47ed02acbbb66ee8a3fe0275bd98add0aa607c3".to_string(), + ); + + get_source_address_bytes(str).expect("address bytes from un-prefixed hex works"); + + let str = String::::from( + "0xd47ed02acbbb66ee8a3fe0275bd98add0aa607c3".to_string(), + ); - H256::from(bytes) + get_source_address_bytes(str).expect("address bytes from prefixed hex works"); } } diff --git a/pallets/liquidity-pools-gateway/routers/Cargo.toml b/pallets/liquidity-pools-gateway/routers/Cargo.toml index d0ba8b5395..fae92ee6ea 100644 --- a/pallets/liquidity-pools-gateway/routers/Cargo.toml +++ b/pallets/liquidity-pools-gateway/routers/Cargo.toml @@ -11,6 +11,7 @@ version = "0.0.1" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +hex = { version = "0.4.3", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } diff --git a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs index 137160536f..a5912166fd 100644 --- a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs +++ b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs @@ -15,7 +15,10 @@ use ethabi::{Contract, Function, Param, ParamType, Token}; use frame_support::dispatch::{DispatchError, DispatchResult}; use frame_system::pallet_prelude::OriginFor; use scale_info::{ - prelude::string::{String, ToString}, + prelude::{ + format, + string::{String, ToString}, + }, TypeInfo, }; use sp_core::{bounded::BoundedVec, ConstU32, H160}; @@ -155,7 +158,11 @@ pub(crate) fn get_axelar_encoded_msg( .map_err(|_| "cannot retrieve Axelar contract function")? .encode_input(&[ Token::String(target_chain_string), - Token::String(target_contract.to_string()), + // Ensure that the target contract is correctly converted to hex. + // + // The `to_string` method on the H160 is returning a string containing an ellipsis, such + // as: 0x1234…7890 + Token::String(format!("0x{}", hex::encode(target_contract.0))), Token::Bytes(encoded_liquidity_pools_contract), ]) .map_err(|_| "cannot encode input for Axelar contract function")?; diff --git a/pallets/order-book/src/benchmarking.rs b/pallets/order-book/src/benchmarking.rs index b82add47f7..7e5190ac54 100644 --- a/pallets/order-book/src/benchmarking.rs +++ b/pallets/order-book/src/benchmarking.rs @@ -12,10 +12,7 @@ #![cfg(feature = "runtime-benchmarks")] -use cfg_types::{ - fixed_point::Rate, - tokens::{CurrencyId, CustomMetadata}, -}; +use cfg_types::tokens::{CurrencyId, CustomMetadata}; use frame_benchmarking::*; use frame_support::traits::fungibles::Mutate as FungiblesMutate; use frame_system::RawOrigin; @@ -31,33 +28,33 @@ const CURRENCY_1: u128 = 1_000_000_000_000; benchmarks! { where_clause { where - T: Config, + T: Config, ::AssetRegistry: orml_traits::asset_registry::Mutate, } create_order { let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; - }:create_order(RawOrigin::Signed(account_0.clone()), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap()) + }:create_order(RawOrigin::Signed(account_0.clone()), asset_0, asset_1, 100 * CURRENCY_0, T::SellRatio::saturating_from_integer(2)) user_update_order { let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; - let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, T::SellRatio::saturating_from_integer(2).into(), 100 * CURRENCY_0)?; - }:user_update_order(RawOrigin::Signed(account_0.clone()), order_id, 150 * CURRENCY_0, Rate::checked_from_integer(1u32).unwrap()) + }:user_update_order(RawOrigin::Signed(account_0.clone()), order_id, 150 * CURRENCY_0, T::SellRatio::saturating_from_integer(1)) user_cancel_order { let (account_0, _, asset_0, asset_1) = set_up_users_currencies::()?; - let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, T::SellRatio::saturating_from_integer(2).into(), 100 * CURRENCY_0)?; }:user_cancel_order(RawOrigin::Signed(account_0.clone()), order_id) fill_order_full { let (account_0, account_1, asset_0, asset_1) = set_up_users_currencies::()?; - let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, Rate::checked_from_integer(2u32).unwrap().into(), 100 * CURRENCY_0)?; + let order_id = Pallet::::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, T::SellRatio::saturating_from_integer(2).into(), 100 * CURRENCY_0)?; }:fill_order_full(RawOrigin::Signed(account_1.clone()), order_id) diff --git a/pallets/order-book/src/mock.rs b/pallets/order-book/src/mock.rs index be9490a551..d558b87aea 100644 --- a/pallets/order-book/src/mock.rs +++ b/pallets/order-book/src/mock.rs @@ -28,6 +28,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, + FixedU128, }; use crate as order_book; @@ -218,7 +219,7 @@ impl order_book::Config for Runtime { type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; type RuntimeEvent = RuntimeEvent; - type SellRatio = cfg_types::fixed_point::Rate; + type SellRatio = FixedU128; type TradeableAsset = Tokens; type Weights = (); } diff --git a/pallets/order-book/src/tests.rs b/pallets/order-book/src/tests.rs index 51104b752b..67f6f4b32b 100644 --- a/pallets/order-book/src/tests.rs +++ b/pallets/order-book/src/tests.rs @@ -10,9 +10,9 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_types::{fixed_point::Rate, tokens::CurrencyId}; +use cfg_types::tokens::CurrencyId; use frame_support::{assert_err, assert_noop, assert_ok, dispatch::RawOrigin}; -use sp_runtime::{traits::Zero, DispatchError, FixedPointNumber}; +use sp_runtime::{traits::Zero, DispatchError, FixedPointNumber, FixedU128}; use super::*; use crate::mock::*; @@ -156,7 +156,7 @@ fn create_order_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3, 2).unwrap() + FixedU128::checked_from_rational(3, 2).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_eq!( @@ -168,7 +168,7 @@ fn create_order_works() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -182,7 +182,7 @@ fn create_order_works() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -202,14 +202,14 @@ fn user_update_order_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3, 2).unwrap() + FixedU128::checked_from_rational(3, 2).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_ok!(OrderBook::user_update_order( RuntimeOrigin::signed(ACCOUNT_0), order_id, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(2u32).unwrap(), + FixedU128::checked_from_integer(2u32).unwrap(), )); assert_eq!( @@ -221,7 +221,7 @@ fn user_update_order_works() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 15 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_integer(2u32).unwrap(), min_fulfillment_amount: 15 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 30 * CURRENCY_USDT_DECIMALS }) @@ -237,7 +237,7 @@ fn user_update_order_only_works_for_valid_account() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3, 2).unwrap() + FixedU128::checked_from_rational(3, 2).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_err!( @@ -245,7 +245,7 @@ fn user_update_order_only_works_for_valid_account() { RuntimeOrigin::signed(ACCOUNT_1), order_id, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(2u32).unwrap(), + FixedU128::checked_from_integer(2u32).unwrap(), ), Error::::Unauthorised ); @@ -260,7 +260,7 @@ fn user_cancel_order_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap() + FixedU128::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; assert_ok!(OrderBook::user_cancel_order( @@ -292,7 +292,7 @@ fn user_cancel_order_only_works_for_valid_account() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap() + FixedU128::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -310,7 +310,7 @@ fn user_cancel_order_only_works_for_valid_account() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -326,7 +326,7 @@ fn fill_order_full_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap() + FixedU128::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; // verify fulfill runs @@ -388,7 +388,7 @@ fn fill_order_full_checks_asset_in_for_fulfiller() { CurrencyId::Native, DEV_AUSD_CURRENCY_ID, 400 * CURRENCY_NATIVE_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap() + FixedU128::checked_from_rational(3u32, 2u32).unwrap() )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; // verify fulfill runs @@ -408,7 +408,7 @@ fn place_order_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 100 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -421,7 +421,7 @@ fn place_order_works() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -436,7 +436,7 @@ fn place_order_works() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -464,7 +464,7 @@ fn place_order_works() { currency_out: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, min_fulfillment_amount: 100 * CURRENCY_AUSD_DECIMALS, - sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap(), + sell_rate_limit: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), }) ); }) @@ -478,7 +478,7 @@ fn place_order_bases_max_sell_off_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 10 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -491,7 +491,7 @@ fn place_order_bases_max_sell_off_buy() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 100 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 10 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 150 * CURRENCY_USDT_DECIMALS }) @@ -506,7 +506,7 @@ fn place_order_bases_max_sell_off_buy() { currency_out: DEV_USDT_CURRENCY_ID, buy_amount: 100 * CURRENCY_AUSD_DECIMALS, min_fulfillment_amount: 10 * CURRENCY_AUSD_DECIMALS, - sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap(), + sell_rate_limit: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), }) ); }) @@ -520,7 +520,7 @@ fn ensure_nonce_updates_order_correctly() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 100 * CURRENCY_AUSD_DECIMALS )); assert_ok!(OrderBook::place_order( @@ -528,7 +528,7 @@ fn ensure_nonce_updates_order_correctly() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 100 * CURRENCY_AUSD_DECIMALS )); let [(order_id_0, _), (order_id_1, _)] = get_account_orders(ACCOUNT_0) @@ -547,7 +547,7 @@ fn place_order_requires_no_min_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 1 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 1 * CURRENCY_AUSD_DECIMALS, ),); }) @@ -562,7 +562,7 @@ fn create_order_requires_min_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 1 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), ), Error::::InsufficientOrderSize ); @@ -578,7 +578,7 @@ fn place_order_requires_pair_with_defined_min() { DEV_AUSD_CURRENCY_ID, FOREIGN_CURRENCY_NO_MIN_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 1 * CURRENCY_AUSD_DECIMALS, ), Error::::InvalidTradingPair @@ -595,7 +595,7 @@ fn place_order_requires_non_zero_min_fulfillment() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 0 ), Error::::InvalidMinimumFulfillment @@ -612,7 +612,7 @@ fn place_order_min_fulfillment_cannot_be_less_than_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 11 * CURRENCY_AUSD_DECIMALS ), Error::::InvalidBuyAmount @@ -629,7 +629,7 @@ fn place_order_requires_non_zero_price() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::zero(), + FixedU128::zero(), 100 * CURRENCY_AUSD_DECIMALS ), Error::::InvalidMaxPrice @@ -645,7 +645,7 @@ fn cancel_order_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 100 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 100 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -690,7 +690,7 @@ fn update_order_works_with_order_increase() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -698,7 +698,7 @@ fn update_order_works_with_order_increase() { ACCOUNT_0, order_id, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(2u32).unwrap(), + FixedU128::checked_from_integer(2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); assert_eq!( @@ -710,7 +710,7 @@ fn update_order_works_with_order_increase() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 15 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_integer(2u32).unwrap(), min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 30 * CURRENCY_USDT_DECIMALS }) @@ -725,7 +725,7 @@ fn update_order_works_with_order_increase() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 15 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_integer(2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_integer(2u32).unwrap(), min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 30 * CURRENCY_USDT_DECIMALS }) @@ -758,7 +758,7 @@ fn update_order_works_with_order_increase() { account: ACCOUNT_0, buy_amount: 15 * CURRENCY_AUSD_DECIMALS, min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, - sell_rate_limit: Rate::checked_from_integer(2u32).unwrap() + sell_rate_limit: FixedU128::checked_from_integer(2u32).unwrap() }) ); }) @@ -774,7 +774,7 @@ fn update_order_updates_min_fulfillment() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -782,7 +782,7 @@ fn update_order_updates_min_fulfillment() { ACCOUNT_0, order_id, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 6 * CURRENCY_AUSD_DECIMALS )); assert_eq!( @@ -795,7 +795,7 @@ fn update_order_updates_min_fulfillment() { buy_amount: 10 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 15 * CURRENCY_USDT_DECIMALS }) @@ -811,7 +811,7 @@ fn update_order_updates_min_fulfillment() { buy_amount: 10 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 10 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_rational(3u32, 2u32).unwrap(), + max_sell_rate: FixedU128::checked_from_rational(3u32, 2u32).unwrap(), min_fulfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 15 * CURRENCY_USDT_DECIMALS }) @@ -826,7 +826,7 @@ fn update_order_updates_min_fulfillment() { account: ACCOUNT_0, buy_amount: 10 * CURRENCY_AUSD_DECIMALS, min_fulfillment_amount: 6 * CURRENCY_AUSD_DECIMALS, - sell_rate_limit: Rate::checked_from_rational(3u32, 2u32).unwrap() + sell_rate_limit: FixedU128::checked_from_rational(3u32, 2u32).unwrap() }) ); }) @@ -840,7 +840,7 @@ fn update_order_works_with_order_decrease() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -848,7 +848,7 @@ fn update_order_works_with_order_decrease() { ACCOUNT_0, order_id, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(1u32).unwrap(), + FixedU128::checked_from_integer(1u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); assert_eq!( @@ -860,7 +860,7 @@ fn update_order_works_with_order_decrease() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 10 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 15 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_integer(1u32).unwrap(), + max_sell_rate: FixedU128::checked_from_integer(1u32).unwrap(), min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 10 * CURRENCY_USDT_DECIMALS }) @@ -875,7 +875,7 @@ fn update_order_works_with_order_decrease() { asset_out_id: DEV_USDT_CURRENCY_ID, buy_amount: 10 * CURRENCY_AUSD_DECIMALS, initial_buy_amount: 15 * CURRENCY_AUSD_DECIMALS, - max_sell_rate: Rate::checked_from_integer(1u32).unwrap(), + max_sell_rate: FixedU128::checked_from_integer(1u32).unwrap(), min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, max_sell_amount: 10 * CURRENCY_USDT_DECIMALS }) @@ -908,7 +908,7 @@ fn update_order_works_with_order_decrease() { account: ACCOUNT_0, buy_amount: 10 * CURRENCY_AUSD_DECIMALS, min_fulfillment_amount: 5 * CURRENCY_AUSD_DECIMALS, - sell_rate_limit: Rate::checked_from_integer(1u32).unwrap() + sell_rate_limit: FixedU128::checked_from_integer(1u32).unwrap() }) ); }) @@ -922,7 +922,7 @@ fn update_order_requires_no_min_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -930,7 +930,7 @@ fn update_order_requires_no_min_buy() { ACCOUNT_0, order_id, 1 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(1u32).unwrap(), + FixedU128::checked_from_integer(1u32).unwrap(), 1 * CURRENCY_AUSD_DECIMALS ),); }) @@ -944,7 +944,7 @@ fn user_update_order_requires_min_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -953,7 +953,7 @@ fn user_update_order_requires_min_buy() { RuntimeOrigin::signed(ACCOUNT_0), order_id, 1 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(1u32).unwrap(), + FixedU128::checked_from_integer(1u32).unwrap(), ), Error::::InsufficientOrderSize ); @@ -968,7 +968,7 @@ fn update_order_requires_non_zero_min_fulfillment() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -977,7 +977,7 @@ fn update_order_requires_non_zero_min_fulfillment() { ACCOUNT_0, order_id, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(1u32).unwrap(), + FixedU128::checked_from_integer(1u32).unwrap(), 0 ), Error::::InvalidMinimumFulfillment @@ -993,7 +993,7 @@ fn update_order_min_fulfillment_cannot_be_less_than_buy() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -1002,7 +1002,7 @@ fn update_order_min_fulfillment_cannot_be_less_than_buy() { ACCOUNT_0, order_id, 10 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_integer(1u32).unwrap(), + FixedU128::checked_from_integer(1u32).unwrap(), 15 * CURRENCY_AUSD_DECIMALS, ), Error::::InvalidBuyAmount @@ -1018,7 +1018,7 @@ fn update_order_requires_non_zero_price() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; @@ -1027,7 +1027,7 @@ fn update_order_requires_non_zero_price() { ACCOUNT_0, order_id, 10 * CURRENCY_AUSD_DECIMALS, - Rate::zero(), + FixedU128::zero(), 15 * CURRENCY_AUSD_DECIMALS, ), Error::::InvalidMaxPrice @@ -1043,7 +1043,7 @@ fn get_order_details_works() { DEV_AUSD_CURRENCY_ID, DEV_USDT_CURRENCY_ID, 15 * CURRENCY_AUSD_DECIMALS, - Rate::checked_from_rational(3u32, 2u32).unwrap(), + FixedU128::checked_from_rational(3u32, 2u32).unwrap(), 5 * CURRENCY_AUSD_DECIMALS )); let (order_id, _) = get_account_orders(ACCOUNT_0).unwrap()[0]; diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 97ba04928b..e2792b5533 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -29,7 +29,7 @@ pub use cfg_types::tokens::CurrencyId; use cfg_types::{ consts::pools::*, fee_keys::FeeKey, - fixed_point::{Quantity, Rate}, + fixed_point::{Quantity, Rate, Ratio}, ids::PRICE_ORACLE_PALLET_ID, oracles::OracleKey, permissions::{PermissionRoles, PermissionScope, PermissionedCurrencyRole, PoolRole, Role}, @@ -1389,8 +1389,8 @@ impl pallet_xcm_transactor::Config for Runtime { } parameter_types! { - pub DefaultTokenSellRate: Rate = Rate::one(); - pub StableToStableRate: Rate = Rate::one(); + pub DefaultTokenSellRate: Ratio = Ratio::one(); + pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { @@ -1399,7 +1399,7 @@ impl pallet_foreign_investments::Config for Runtime { pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = @@ -1409,7 +1409,7 @@ impl pallet_foreign_investments::Config for Runtime { type InvestmentId = TrancheCurrency; type PoolId = PoolId; type PoolInspect = PoolSystem; - type Rate = Rate; + type Rate = Ratio; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; type TokenSwaps = OrderBook; @@ -1811,7 +1811,7 @@ impl pallet_order_book::Config for Runtime { type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; type RuntimeEvent = RuntimeEvent; - type SellRatio = Rate; + type SellRatio = Ratio; type TradeableAsset = Tokens; type Weights = weights::pallet_order_book::WeightInfo; } @@ -2177,7 +2177,7 @@ impl_runtime_apis! { } } - impl runtime_common::apis::PoolsApi for Runtime { + impl runtime_common::apis::PoolsApi for Runtime { fn currency(pool_id: PoolId) -> Option{ pallet_pool_system::Pool::::get(pool_id).map(|details| details.currency) } @@ -2192,7 +2192,7 @@ impl_runtime_apis! { ).ok() } - fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ + fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; @@ -2205,14 +2205,14 @@ impl_runtime_apis! { prices.get(index).cloned() } - fn tranche_token_prices(pool_id: PoolId) -> Option>{ + fn tranche_token_prices(pool_id: PoolId) -> Option>{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; let total_assets = pool.reserve.total.saturating_add(nav); pool .tranches - .calculate_prices::(total_assets, now) + .calculate_prices::<_, OrmlTokens, AccountId>(total_assets, now) .ok() } diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index c15b9bcbee..df719541ce 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -30,7 +30,7 @@ use cfg_types::{ consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes}, domain_address::{Domain, DomainAddress}, fee_keys::FeeKey, - fixed_point::{Quantity, Rate}, + fixed_point::{Quantity, Rate, Ratio}, ids::PRICE_ORACLE_PALLET_ID, oracles::OracleKey, permissions::{ @@ -430,8 +430,8 @@ impl orml_asset_registry::Config for Runtime { } parameter_types! { - pub DefaultTokenSellRate: Rate = Rate::one(); - pub StableToStableRate: Rate = Rate::one(); + pub DefaultTokenSellRate: Ratio = Ratio::one(); + pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { @@ -440,7 +440,7 @@ impl pallet_foreign_investments::Config for Runtime { pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = @@ -450,8 +450,7 @@ impl pallet_foreign_investments::Config for Runtime { type InvestmentId = TrancheCurrency; type PoolId = PoolId; type PoolInspect = PoolSystem; - // TODO: Switch to ratio after merging #1546 - type Rate = Rate; + type Rate = Ratio; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; type TokenSwaps = OrderBook; @@ -465,6 +464,8 @@ parameter_types! { } impl pallet_liquidity_pools::Config for Runtime { + // NOTE: No need to adapt that. The Router is an artifact and will be removed + // with FI PR type AdminOrigin = EnsureRootOr; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; @@ -1965,7 +1966,7 @@ impl pallet_order_book::Config for Runtime { type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; type RuntimeEvent = RuntimeEvent; - type SellRatio = Rate; + type SellRatio = Ratio; type TradeableAsset = Tokens; type Weights = weights::pallet_order_book::WeightInfo; } @@ -2255,7 +2256,7 @@ impl_runtime_apis! { } // PoolsApi - impl runtime_common::apis::PoolsApi for Runtime { + impl runtime_common::apis::PoolsApi for Runtime { fn currency(pool_id: PoolId) -> Option{ pallet_pool_system::Pool::::get(pool_id).map(|details| details.currency) } @@ -2270,7 +2271,7 @@ impl_runtime_apis! { ).ok() } - fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ + fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; @@ -2283,14 +2284,14 @@ impl_runtime_apis! { prices.get(index).cloned() } - fn tranche_token_prices(pool_id: PoolId) -> Option>{ + fn tranche_token_prices(pool_id: PoolId) -> Option>{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; let total_assets = pool.reserve.total.saturating_add(nav); pool .tranches - .calculate_prices::(total_assets, now) + .calculate_prices::<_, Tokens, AccountId>(total_assets, now) .ok() } diff --git a/runtime/common/src/account_conversion.rs b/runtime/common/src/account_conversion.rs index 714fe0a6ab..43443c228d 100644 --- a/runtime/common/src/account_conversion.rs +++ b/runtime/common/src/account_conversion.rs @@ -75,6 +75,7 @@ impl Convert<(Domain, [u8; 32]), AccountId> for AccountConverte } } } + impl TryConvert for AccountConverter where XcmConverter: xcm_executor::traits::Convert, diff --git a/runtime/common/src/evm/precompile.rs b/runtime/common/src/evm/precompile.rs index cf0987f909..c204976fb6 100644 --- a/runtime/common/src/evm/precompile.rs +++ b/runtime/common/src/evm/precompile.rs @@ -46,7 +46,7 @@ const ECRECOVERPUBLICKEY_ADDR: Addr = addr(1026); /// Liquidity-Pool logic on centrifuge. /// /// The precompile implements -const LP_AXELAR_GATEWAY: Addr = addr(2048); +pub const LP_AXELAR_GATEWAY: Addr = addr(2048); pub struct CentrifugePrecompiles(PhantomData); diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 417c21113e..e369361d65 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -424,7 +424,7 @@ pub mod xcm_transactor { pub mod foreign_investments { use cfg_primitives::{conversion::convert_balance_decimals, Balance}; use cfg_traits::SimpleCurrencyConversion; - use cfg_types::{fixed_point::Rate, tokens::CurrencyId}; + use cfg_types::{fixed_point::Ratio, tokens::CurrencyId}; use frame_support::pallet_prelude::PhantomData; use orml_traits::asset_registry::Inspect; use sp_runtime::{ @@ -442,19 +442,19 @@ pub mod foreign_investments { /// NOTE: Should be deprecated ASAP! // TODO(@review): Can we determine whether a ForeignAsset is a stable coin at // this point of time? - pub struct SimpleStableCurrencyConverter( - PhantomData<(AssetRegistry, StableToStableRate)>, + pub struct SimpleStableCurrencyConverter( + PhantomData<(AssetRegistry, StableToStableRatio)>, ); - impl SimpleCurrencyConversion - for SimpleStableCurrencyConverter + impl SimpleCurrencyConversion + for SimpleStableCurrencyConverter where AssetRegistry: Inspect< AssetId = CurrencyId, Balance = Balance, CustomMetadata = cfg_types::tokens::CustomMetadata, >, - StableToStableRate: Get, + StableToStableRatio: Get, { type Balance = Balance; type Currency = CurrencyId; @@ -481,7 +481,7 @@ pub mod foreign_investments { convert_balance_decimals( from_metadata.decimals, to_metadata.decimals, - StableToStableRate::get().ensure_mul_int(amount_out)?, + StableToStableRatio::get().ensure_mul_int(amount_out)?, ) .map_err(DispatchError::from) } diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index 83512c9575..6c987d17b2 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "development-runtime" -version = "0.10.21" +version = "0.10.23" authors = ["Centrifuge "] edition = "2021" build = "build.rs" diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 7e6ffed66c..c6d8af2e22 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -30,7 +30,7 @@ use cfg_traits::{ use cfg_types::{ consts::pools::*, fee_keys::FeeKey, - fixed_point::{Quantity, Rate}, + fixed_point::{Quantity, Rate, Ratio}, ids::PRICE_ORACLE_PALLET_ID, locations::Location, oracles::OracleKey, @@ -138,7 +138,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1022, + spec_version: 1023, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1545,8 +1545,8 @@ impl orml_asset_registry::Config for Runtime { } parameter_types! { - pub DefaultTokenSellRate: Rate = Rate::one(); - pub StableToStableRate: Rate = Rate::one(); + pub DefaultTokenSellRate: Ratio = Ratio::one(); + pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { @@ -1555,7 +1555,7 @@ impl pallet_foreign_investments::Config for Runtime { pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = @@ -1565,8 +1565,7 @@ impl pallet_foreign_investments::Config for Runtime { type InvestmentId = TrancheCurrency; type PoolId = PoolId; type PoolInspect = PoolSystem; - // TODO: Switch to ratio after merging #1546 - type Rate = Rate; + type Rate = Ratio; type RuntimeEvent = RuntimeEvent; type TokenSwapOrderId = u64; type TokenSwaps = OrderBook; @@ -1863,7 +1862,7 @@ impl pallet_order_book::Config for Runtime { type OrderIdNonce = u64; type OrderPairVecSize = OrderPairVecSize; type RuntimeEvent = RuntimeEvent; - type SellRatio = Rate; + type SellRatio = Ratio; type TradeableAsset = Tokens; type Weights = weights::pallet_order_book::WeightInfo; } @@ -2246,7 +2245,7 @@ impl_runtime_apis! { } // PoolsApi - impl runtime_common::apis::PoolsApi for Runtime { + impl runtime_common::apis::PoolsApi for Runtime { fn currency(pool_id: PoolId) -> Option{ pallet_pool_system::Pool::::get(pool_id).map(|details| details.currency) } @@ -2261,7 +2260,7 @@ impl_runtime_apis! { ).ok() } - fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ + fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; @@ -2274,14 +2273,14 @@ impl_runtime_apis! { prices.get(index).cloned() } - fn tranche_token_prices(pool_id: PoolId) -> Option>{ + fn tranche_token_prices(pool_id: PoolId) -> Option>{ let now = ::now().as_secs(); let mut pool = PoolSystem::pool(pool_id)?; let nav = Loans::update_nav(pool_id).ok()?; let total_assets = pool.reserve.total.saturating_add(nav); pool .tranches - .calculate_prices::(total_assets, now) + .calculate_prices::<_, OrmlTokens, AccountId>(total_assets, now) .ok() } diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index e3975b8c3d..6ec4036e5c 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -88,12 +88,14 @@ cfg-traits = { path = "../../libs/traits" } cfg-types = { path = "../../libs/types" } cfg-utils = { path = "../../libs/utils" } +ethabi = { version = "16.0", default-features = false } ethereum = { version = "0.14.0", default-features = false } pallet-ethereum = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } pallet-evm = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } pallet-evm-chain-id = { git = "https://github.com/PureStake/frontier", default-features = false, branch = "moonbeam-polkadot-v0.9.38" } +axelar-gateway-precompile = { path = "../../pallets/liquidity-pools-gateway/axelar-gateway-precompile" } liquidity-pools-gateway-routers = { path = "../../pallets/liquidity-pools-gateway/routers" } pallet-block-rewards = { path = "../../pallets/block-rewards" } pallet-ethereum-transaction = { path = "../../pallets/ethereum-transaction" } @@ -170,6 +172,7 @@ std = [ "pallet-collective/std", "pallet-democracy/std", "pallet-preimage/std", + "ethabi/std", ] runtime-benchmarks = [ diff --git a/runtime/integration-tests/src/ethereum_transaction/pallet.rs b/runtime/integration-tests/src/evm/ethereum_transaction.rs similarity index 99% rename from runtime/integration-tests/src/ethereum_transaction/pallet.rs rename to runtime/integration-tests/src/evm/ethereum_transaction.rs index 92713adfac..b29f0a5681 100644 --- a/runtime/integration-tests/src/ethereum_transaction/pallet.rs +++ b/runtime/integration-tests/src/evm/ethereum_transaction.rs @@ -25,7 +25,6 @@ use crate::{ AccountId, CouncilCollective, FastTrackVotingPeriod, MinimumDeposit, Runtime, RuntimeCall, RuntimeEvent, PARA_ID, }, - ethereum_transaction::pallet, utils::{ env, env::{ChainState, EventRange, TestEnv}, diff --git a/runtime/integration-tests/src/ethereum_transaction/mod.rs b/runtime/integration-tests/src/evm/mod.rs similarity index 93% rename from runtime/integration-tests/src/ethereum_transaction/mod.rs rename to runtime/integration-tests/src/evm/mod.rs index 0ca88fbd73..99172b9fdb 100644 --- a/runtime/integration-tests/src/ethereum_transaction/mod.rs +++ b/runtime/integration-tests/src/evm/mod.rs @@ -10,4 +10,5 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -mod pallet; +mod ethereum_transaction; +mod precompile; diff --git a/runtime/integration-tests/src/evm/precompile.rs b/runtime/integration-tests/src/evm/precompile.rs new file mode 100644 index 0000000000..2abb953735 --- /dev/null +++ b/runtime/integration-tests/src/evm/precompile.rs @@ -0,0 +1,232 @@ +// Copyright 2023 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 std::collections::BTreeMap; + +use axelar_gateway_precompile::SourceConverter; +use cfg_primitives::{Balance, PoolId, TrancheId, CFG}; +use cfg_traits::{ethereum::EthereumTransactor, liquidity_pools::Codec}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + fixed_point::Rate, + tokens::{CurrencyId, CustomMetadata, GeneralCurrencyIndex}, +}; +use codec::Encode; +use ethabi::{Contract, Function, Param, ParamType, Token}; +use ethereum::{LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2}; +use frame_support::{assert_err, assert_ok, dispatch::RawOrigin}; +use fudge::primitives::Chain; +use hex::ToHex; +use orml_traits::{asset_registry::AssetMetadata, MultiCurrency}; +use pallet_evm::{AddressMapping, FeeCalculator}; +use pallet_liquidity_pools::Message; +use runtime_common::{account_conversion::AccountConverter, evm::precompile::LP_AXELAR_GATEWAY}; +use sp_core::{Get, H160, H256, U256}; +use sp_runtime::traits::{BlakeTwo256, Hash}; +use tokio::runtime::Handle; +use xcm::{v3::MultiLocation, VersionedMultiLocation}; + +use crate::{ + chain::centrifuge::{ + AccountId, CouncilCollective, FastTrackVotingPeriod, MinimumDeposit, Runtime, RuntimeCall, + RuntimeEvent, RuntimeOrigin, PARA_ID, + }, + evm::ethereum_transaction::TEST_CONTRACT_CODE, + utils::{ + env, + env::{ChainState, EventRange, TestEnv}, + evm::{deploy_contract, mint_balance_into_derived_account}, + }, +}; + +#[tokio::test] +async fn axelar_precompile_execute() { + let mut env = env::test_env_default(Handle::current()); + + env.evolve().unwrap(); + + let currency_id = CurrencyId::ForeignAsset(123456); + + let sender_address = H160::from_low_u64_be(1_000_002); + + mint_balance_into_derived_account(&mut env, sender_address, 1_000_000 * CFG); + + let derived_sender_account = env + .with_state(Chain::Para(PARA_ID), || { + ::AddressMapping::into_account_id(sender_address) + }) + .unwrap(); + + let receiver_address = H160::from_low_u64_be(1_000_003); + + let derived_receiver_account = env + .with_state(Chain::Para(PARA_ID), || { + ::AddressMapping::into_account_id(receiver_address) + }) + .unwrap(); + + env.with_state(Chain::Para(PARA_ID), || { + let derived_receiver_balance = + orml_tokens::Pallet::::free_balance(currency_id, &derived_receiver_account); + + assert_eq!(derived_receiver_balance, 0) + }) + .unwrap(); + + let source_address = H160::from_low_u64_be(1111); + let evm_chain_name = String::from("Ethereum"); + let evm_chain_id = 0; + + let currency_metadata = AssetMetadata { + decimals: 18, + name: "Test".into(), + symbol: "TST".into(), + existential_deposit: 1_000_000, + location: Some(VersionedMultiLocation::V3(MultiLocation::here())), + additional: CustomMetadata { + transferability: Default::default(), + mintable: true, + permissioned: false, + pool_currency: false, + }, + }; + + env.with_mut_state(Chain::Para(PARA_ID), || { + orml_asset_registry::Pallet::::register_asset( + RuntimeOrigin::root(), + currency_metadata, + Some(currency_id), + ) + .unwrap(); + + orml_tokens::Pallet::::deposit( + currency_id, + &derived_sender_account, + 1_000_000_000_000 * 10u128.saturating_pow(18), + ) + .unwrap(); + }) + .unwrap(); + + let general_currency_id = env + .with_state(Chain::Para(PARA_ID), || { + pallet_liquidity_pools::Pallet::::try_get_general_index(currency_id).unwrap() + }) + .unwrap(); + + let transfer_amount = 100; + let msg = Message::::Transfer { + currency: general_currency_id, + sender: derived_sender_account.clone().into(), + receiver: derived_receiver_account.clone().into(), + amount: transfer_amount, + }; + + env.with_mut_state(Chain::Para(PARA_ID), || { + axelar_gateway_precompile::Pallet::::set_gateway( + RuntimeOrigin::root(), + sender_address, + ) + .unwrap(); + + axelar_gateway_precompile::Pallet::::set_converter( + RuntimeOrigin::root(), + BlakeTwo256::hash(evm_chain_name.as_bytes()), + SourceConverter { + domain: Domain::EVM(evm_chain_id), + }, + ) + .unwrap(); + + pallet_liquidity_pools_gateway::Pallet::::add_instance( + RuntimeOrigin::root(), + DomainAddress::EVM(evm_chain_id, source_address.0), + ) + .unwrap(); + }); + + let command_id = H256::from_low_u64_be(5678); + + let test_input = Contract { + constructor: None, + functions: BTreeMap::>::from([( + "execute".into(), + vec![Function { + name: "execute".into(), + inputs: vec![ + Param { + name: "commandId".into(), + kind: ParamType::FixedBytes(32), + internal_type: None, + }, + Param { + name: "sourceChain".into(), + kind: ParamType::String, + internal_type: None, + }, + Param { + name: "sourceAddress".into(), + kind: ParamType::String, + internal_type: None, + }, + Param { + name: "payload".into(), + kind: ParamType::Bytes, + internal_type: None, + }, + ], + outputs: vec![], + constant: false, + state_mutability: Default::default(), + }], + )]), + events: Default::default(), + errors: Default::default(), + receive: false, + fallback: false, + } + .function("execute".into()) + .map_err(|_| "cannot retrieve test contract function") + .unwrap() + .encode_input(&[ + Token::FixedBytes(command_id.0.to_vec()), + Token::String(evm_chain_name), + Token::String(String::from_utf8(source_address.as_fixed_bytes().to_vec()).unwrap()), + Token::Bytes(msg.serialize()), + ]) + .map_err(|_| "cannot encode input for test contract function") + .unwrap(); + + env.with_mut_state(Chain::Para(PARA_ID), || { + assert_ok!(pallet_evm::Pallet::::call( + RawOrigin::Signed(derived_sender_account.clone()).into(), + sender_address, + LP_AXELAR_GATEWAY.into(), + test_input.to_vec(), + U256::from(0), + 0x100000, + U256::from(1_000_000_000), + None, + Some(U256::from(0)), + Vec::new(), + )); + }) + .unwrap(); + + env.with_state(Chain::Para(PARA_ID), || { + let derived_receiver_balance = + orml_tokens::Pallet::::free_balance(currency_id, &derived_receiver_account); + + assert_eq!(derived_receiver_balance, transfer_amount) + }) + .unwrap(); +} diff --git a/runtime/integration-tests/src/lib.rs b/runtime/integration-tests/src/lib.rs index c2842655c9..25636495d4 100644 --- a/runtime/integration-tests/src/lib.rs +++ b/runtime/integration-tests/src/lib.rs @@ -14,7 +14,7 @@ #![cfg(test)] #![allow(unused)] -mod ethereum_transaction; +mod evm; mod liquidity_pools; mod pools; mod rewards; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 1f7554f347..ba7f441799 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -30,7 +30,7 @@ use cfg_traits::{ }; use cfg_types::{ domain_address::{Domain, DomainAddress}, - fixed_point::{Quantity, Rate}, + fixed_point::{Quantity, Ratio}, investments::{CollectedAmount, InvestCollection, InvestmentAccount, RedeemCollection, Swap}, orders::FulfillmentWithPrice, permissions::{PermissionScope, PoolRole, Role, UNION}, @@ -43,7 +43,7 @@ use cfg_types::{ use development_runtime::{ Balances, ForeignInvestments, Investments, LiquidityPools, LocationToAccountId, OrmlAssetRegistry, Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, - StableToStableRate, System, Tokens, + StableToStableRatio, System, Tokens, }; use frame_support::{ assert_noop, assert_ok, @@ -1483,7 +1483,7 @@ mod mismatching_currencies { register_usdt(); let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >::stable_to_stable( foreign_currency, pool_currency, @@ -1683,7 +1683,7 @@ mod mismatching_currencies { )); let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >::stable_to_stable( foreign_currency, pool_currency, @@ -1738,7 +1738,7 @@ mod mismatching_currencies { fulfillment_amount: invest_amount_pool_denominated, currency_in: pool_currency, currency_out: foreign_currency, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), } .into() })); @@ -1804,7 +1804,7 @@ mod mismatching_currencies { fulfillment_amount: invest_amount_foreign_denominated / 2, currency_in: foreign_currency, currency_out: pool_currency, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), } .into() })); @@ -1868,7 +1868,7 @@ mod mismatching_currencies { enable_liquidity_pool_transferability(foreign_currency); let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >::stable_to_stable( foreign_currency, pool_currency, @@ -1988,7 +1988,7 @@ mod mismatching_currencies { order_id: swap_order_id, account: investor.clone(), buy_amount: swap_amount, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), min_fulfillment_amount: swap_amount, } .into() @@ -2037,7 +2037,7 @@ mod mismatching_currencies { order_id: swap_order_id, account: investor.clone(), buy_amount: swap_amount, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), min_fulfillment_amount: swap_amount, } .into() @@ -2058,7 +2058,7 @@ mod mismatching_currencies { fulfillment_amount: invest_amount_foreign_denominated / 4 * 5, currency_in: foreign_currency, currency_out: pool_currency, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), } .into() })); @@ -2110,7 +2110,7 @@ mod mismatching_currencies { enable_liquidity_pool_transferability(foreign_currency); let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >::stable_to_stable( foreign_currency, pool_currency, @@ -2249,7 +2249,7 @@ mod mismatching_currencies { order_id: swap_order_id, account: investor.clone(), buy_amount: invest_amount_pool_denominated / 8 * 7, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), min_fulfillment_amount: invest_amount_pool_denominated / 8 * 7, } .into() @@ -2292,7 +2292,7 @@ mod mismatching_currencies { order_id: swap_order_id, account: investor.clone(), buy_amount: invest_amount_pool_denominated / 4 * 3, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), min_fulfillment_amount: invest_amount_pool_denominated / 4 * 3, } .into() @@ -2375,7 +2375,7 @@ mod mismatching_currencies { fulfillment_amount: remaining_foreign_swap_amount, currency_in: foreign_currency, currency_out: pool_currency, - sell_rate_limit: Rate::one(), + sell_rate_limit: Ratio::one(), } .into() })); @@ -2506,7 +2506,7 @@ mod setup { } else { let amount_pool_denominated: u128 = SimpleStableCurrencyConverter::< OrmlAssetRegistry, - StableToStableRate, + StableToStableRatio, >::stable_to_stable( pool_currency, currency_id, amount ) From 5b1ca4a21338e0d31ea02718fc8c68768e440b84 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 13 Sep 2023 17:18:12 +0200 Subject: [PATCH 88/96] refactor: apply suggestions from code review --- pallets/foreign-investments/src/errors.rs | 43 ++++++++++++------- pallets/foreign-investments/src/hooks.rs | 6 +-- .../foreign-investments/src/impls/invest.rs | 8 ---- pallets/foreign-investments/src/impls/mod.rs | 32 +++----------- pallets/foreign-investments/src/lib.rs | 30 +++++++------ .../routers/src/routers/axelar_evm.rs | 3 -- pallets/liquidity-pools/src/lib.rs | 2 +- pallets/liquidity-pools/src/message.rs | 26 +++++------ runtime/altair/src/lib.rs | 2 +- runtime/centrifuge/src/lib.rs | 2 +- runtime/development/src/lib.rs | 2 +- .../liquidity_pools/foreign_investments.rs | 8 ++-- 12 files changed, 77 insertions(+), 87 deletions(-) diff --git a/pallets/foreign-investments/src/errors.rs b/pallets/foreign-investments/src/errors.rs index 09aa4efc27..a1e670bac2 100644 --- a/pallets/foreign-investments/src/errors.rs +++ b/pallets/foreign-investments/src/errors.rs @@ -15,30 +15,32 @@ use codec::{Decode, Encode}; use frame_support::PalletError; use scale_info::TypeInfo; +use crate::pallet::{Config, Error}; + #[derive(Encode, Decode, TypeInfo, PalletError)] pub enum InvestError { /// Failed to increase the investment. - Increase, - /// Failed to decrease the unprocessed investment. - Decrease, + IncreaseTransition, + /// The desired decreasing amount exceeds the max amount. + DecreaseAmountOverflow, + /// Failed to transition the state as a result of a decrease. + DecreaseTransition, /// Failed to transition after fulfilled swap order. - FulfillSwapOrder, + FulfillSwapOrderTransition, /// Failed to transition a (partially) processed investment after /// collecting. - Collect, + CollectTransition, /// The investment needs to be collected before it can be updated further. CollectRequired, - /// Attempted to collect an investment which has not been processed yet. - NothingCollected, } #[derive(Encode, Decode, TypeInfo, PalletError)] pub enum RedeemError { /// Failed to increase the redemption. - Increase, + IncreaseTransition, /// Failed to collect the redemption. - Collect, + CollectTransition, /// Failed to retrieve the foreign payout currency for a collected /// redemption. /// @@ -46,13 +48,24 @@ pub enum RedeemError { /// having increased their redemption as this would store the payout /// currency. CollectPayoutCurrencyNotFound, - /// Failed to decrease the unprocessed redemption. - Decrease, + /// The desired decreasing amount exceeds the max amount. + DecreaseAmountOverflow, + /// Failed to transition the state as a result of a decrease. + DecreaseTransition, /// Failed to transition after fulfilled swap order. - FulfillSwapOrder, - /// Failed to transition a (partially) processed redemption after an epoch - /// was executed. - EpochExecution, + FulfillSwapOrderTransition, /// The redemption needs to be collected before it can be updated further. CollectRequired, } + +impl From for Error { + fn from(error: InvestError) -> Self { + Error::::InvestError(error) + } +} + +impl From for Error { + fn from(error: RedeemError) -> Self { + Error::::RedeemError(error) + } +} diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 08e5e6fcea..28dda93e7b 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -76,7 +76,7 @@ impl StatusNotificationHook for FulfilledSwapOrderHook { ensure!( status.amount <= active_invest_swap_amount.ensure_add(active_redeem_swap_amount)?, - DispatchError::Arithmetic(sp_runtime::ArithmeticError::Overflow) + Error::::FulfilledTokenSwapAmountOverflow ); let invest_swap = SwapOf:: { @@ -131,7 +131,7 @@ impl FulfilledSwapOrderHook { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(InvestError::FulfillSwapOrder) + Error::::from(InvestError::FulfillSwapOrderTransition) })?; Pallet::::apply_invest_state_transition( who, @@ -168,7 +168,7 @@ impl FulfilledSwapOrderHook { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("ForeignInvestment state transition error: {:?}", e); - Error::::from(RedeemError::FulfillSwapOrder) + Error::::from(RedeemError::FulfillSwapOrderTransition) })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state) } diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 156de031a6..30358f1a21 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -25,10 +25,6 @@ use crate::types::{InvestState, InvestStateConfig, InvestTransition}; impl InvestState where T: InvestStateConfig, - /* impl InvestState - * where - * Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - * Currency: Clone + Copy + PartialEq + Debug, */ { /// Solely apply state machine to transition one `InvestState` into another /// based on the transition, see . @@ -210,10 +206,6 @@ where impl InvestState where T: InvestStateConfig, - /* impl InvestState - * where - * Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug, - * Currency: Clone + Copy + PartialEq + Debug, */ { /// Handle `increase` transitions depicted by `msg::increase` edges in the /// invest state diagram: diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index 3dc53ad03f..ef0970c89b 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -52,8 +52,6 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - // TODO(future): Add implicit collection or error handling (i.e. message to - // source domain) ensure!( !T::Investment::investment_requires_collect(who, investment_id), Error::::InvestError(InvestError::CollectRequired) @@ -70,7 +68,7 @@ impl ForeignInvestment for Pallet { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Increase) + Error::::from(InvestError::IncreaseTransition) })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state, true)?; Ok(()) @@ -84,8 +82,6 @@ impl ForeignInvestment for Pallet { foreign_currency: T::CurrencyId, pool_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - // TODO(future): Add implicit collection or error handling (i.e. message to - // source domain) ensure!( !T::Investment::investment_requires_collect(who, investment_id), Error::::InvestError(InvestError::CollectRequired) @@ -94,7 +90,7 @@ impl ForeignInvestment for Pallet { let pre_state = InvestmentState::::get(who, investment_id); ensure!( pre_state.get_investing_amount() >= amount, - Error::::InvestError(InvestError::Decrease) + Error::::InvestError(InvestError::DecreaseAmountOverflow) ); let post_state = pre_state @@ -106,7 +102,7 @@ impl ForeignInvestment for Pallet { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Decrease) + Error::::from(InvestError::DecreaseTransition) })?; Pallet::::apply_invest_state_transition(who, investment_id, post_state, true)?; @@ -120,8 +116,6 @@ impl ForeignInvestment for Pallet { amount: T::Balance, payout_currency: T::CurrencyId, ) -> Result<(), DispatchError> { - // TODO(future): This error needs to be communicated to sending domain as it - // cannot be resolved by triggering a bot let currency_matches = RedemptionPayoutCurrency::::mutate(who, investment_id, |maybe_currency| { if let Some(currency) = maybe_currency { @@ -135,8 +129,6 @@ impl ForeignInvestment for Pallet { currency_matches, Error::::InvalidRedemptionPayoutCurrency ); - // TODO(future): Add implicit collection or error handling (i.e. message to - // source domain) ensure!( !T::Investment::redemption_requires_collect(who, investment_id), Error::::RedeemError(RedeemError::CollectRequired) @@ -148,7 +140,7 @@ impl ForeignInvestment for Pallet { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("RedeemState transition error: {:?}", e); - Error::::from(RedeemError::Increase) + Error::::from(RedeemError::IncreaseTransition) })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -162,8 +154,6 @@ impl ForeignInvestment for Pallet { amount: T::Balance, payout_currency: T::CurrencyId, ) -> Result<(T::Balance, T::Balance), DispatchError> { - // TODO(future): This error needs to be communicated to sending domain as it - // cannot be resolved by triggering a bot ensure!( RedemptionPayoutCurrency::::get(who, investment_id) .map(|currency| currency == payout_currency) @@ -173,8 +163,6 @@ impl ForeignInvestment for Pallet { }), Error::::InvalidRedemptionPayoutCurrency ); - // TODO(future): Add implicit collection or error handling (i.e. message to - // source domain) ensure!( !T::Investment::redemption_requires_collect(who, investment_id), Error::::RedeemError(RedeemError::CollectRequired) @@ -185,7 +173,7 @@ impl ForeignInvestment for Pallet { .transition(RedeemTransition::DecreaseRedeemOrder(amount)) .map_err(|e| { log::debug!("RedeemState transition error: {:?}", e); - Error::::from(RedeemError::Decrease) + Error::::from(RedeemError::DecreaseTransition) })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; @@ -721,8 +709,6 @@ impl Pallet { /// Kills all storage associated with token swaps and cancels the /// potentially active swap order. - /// - /// NOTE: Must only be called in `handle_swap_order`. fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { if T::TokenSwaps::is_active(swap_order_id) { @@ -1046,7 +1032,7 @@ impl Pallet { pre_state.transition(InvestTransition::CollectInvestment(investing_amount))?; Self::apply_invest_state_transition(who, investment_id, post_state, true).map_err(|e| { log::debug!("InvestState transition error: {:?}", e); - Error::::from(InvestError::Collect) + Error::::from(InvestError::CollectTransition) })?; Ok(()) @@ -1063,10 +1049,6 @@ impl Pallet { pool_currency: T::CurrencyId, ) -> Result, DispatchError> { let collected = CollectedInvestment::::take(who, investment_id); - ensure!( - !collected.amount_payment.is_zero(), - Error::::InvestError(InvestError::NothingCollected) - ); // Determine payout and remaining amounts in foreign currency instead of current // pool currency denomination @@ -1138,7 +1120,7 @@ impl Pallet { .map_err(|e| { // Inner error holds finer granularity but should never occur log::debug!("RedeemState transition error: {:?}", e); - Error::::from(RedeemError::Collect) + Error::::from(RedeemError::CollectTransition) })?; Pallet::::apply_redeem_state_transition(who, investment_id, post_state)?; diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 6855289d3c..66aca8c74f 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -348,7 +348,9 @@ pub mod pallet { /// Maps an investor and their investment id to the foreign payout currency /// requested on the initial redemption increment. /// - /// NOTE: The lifetime of this storage mirrors the one of `RedemptionState`. + /// TODO(future): The lifetime of this storage is currently defensively + /// indefinite. It should most likely mirror the one of `RedemptionState` + /// though right now it #[pallet::storage] pub type RedemptionPayoutCurrency = StorageDoubleMap< _, @@ -396,21 +398,25 @@ pub mod pallet { /// Failed to retrieve the `TokenSwapReason` from the given /// `TokenSwapOrderId`. TokenSwapReasonNotFound, + /// The fulfilled token swap amount exceeds the sum of active swap + /// amounts of the corresponding `InvestmentState` and + /// `RedemptionState`. + FulfilledTokenSwapAmountOverflow, /// Failed to transition the `InvestState`. InvestError(InvestError), /// Failed to transition the `RedeemState.` RedeemError(RedeemError), } - impl From for Error { - fn from(error: InvestError) -> Self { - Error::::InvestError(error) - } - } - - impl From for Error { - fn from(error: RedeemError) -> Self { - Error::::RedeemError(error) - } - } + // impl From for Error { + // fn from(error: InvestError) -> Self { + // Error::::InvestError(error) + // } + // } + + // impl From for Error { + // fn from(error: RedeemError) -> Self { + // Error::::RedeemError(error) + // } + // } } diff --git a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs index df8c016616..6e7e7bfc9b 100644 --- a/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs +++ b/pallets/liquidity-pools-gateway/routers/src/routers/axelar_evm.rs @@ -87,9 +87,6 @@ pub(crate) fn get_axelar_encoded_msg( target_chain: Vec, target_contract: H160, ) -> Result, &'static str> { - let target_chain_string = - String::from_utf8(target_chain).map_err(|_| "target chain conversion error")?; - #[allow(deprecated)] let encoded_axelar_contract = Contract { constructor: None, diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index ed633d3610..39ff697fe4 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -450,7 +450,7 @@ pub mod pallet { // TODO(future): Once we diverge from 1-to-1 conversions for foreign and pool // currencies, this price must be first converted into the currency_id and then - // re-denominated to 18 decimals (i.e. `BalanceRatio` precision) + // re-denominated to 18 decimals (i.e. `Ratio` precision) let price = T::TrancheTokenPrice::get(pool_id, tranche_id) .ok_or(Error::::MissingTranchePrice)? .price; diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 94d863f419..693481cb88 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -30,13 +30,13 @@ pub const TOKEN_SYMBOL_SIZE: usize = 32; /// corresponding receiver rejects it. #[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug))] -pub enum Message +pub enum Message where Domain: Codec, PoolId: Encode + Decode, TrancheId: Encode + Decode, Balance: Encode + Decode, - Rate: Encode + Decode, + Ratio: Encode + Decode, { Invalid, /// Add a currency to a domain, i.e, register the mapping of a currency id @@ -80,7 +80,7 @@ where pool_id: PoolId, tranche_id: TrancheId, currency: u128, - price: Rate, + price: Ratio, }, /// Whitelist an address for the specified pair of pool and tranche token on /// the target domain. @@ -374,8 +374,8 @@ impl< PoolId: Encode + Decode, TrancheId: Encode + Decode, Balance: Encode + Decode, - Rate: Encode + Decode, - > Message + Ratio: Encode + Decode, + > Message { /// The call type that identifies a specific Message variant. This value is /// used to encode/decode a Message to/from a bytearray, whereas the head of @@ -419,8 +419,8 @@ impl< PoolId: Encode + Decode, TrancheId: Encode + Decode, Balance: Encode + Decode, - Rate: Encode + Decode, - > Codec for Message + Ratio: Encode + Decode, + > Codec for Message { fn serialize(&self) -> Vec { match self { @@ -922,7 +922,7 @@ fn encoded_message(call_type: u8, fields: Vec>) -> Vec { #[cfg(test)] mod tests { use cfg_primitives::{Balance, PoolId, TrancheId}; - use cfg_types::fixed_point::Rate; + use cfg_types::fixed_point::Ratio; use cfg_utils::vec_to_fixed_array; use hex::FromHex; use sp_runtime::traits::One; @@ -930,7 +930,7 @@ mod tests { use super::*; use crate::{Domain, DomainAddress}; - pub type LiquidityPoolsMessage = Message; + pub type LiquidityPoolsMessage = Message; const AMOUNT: Balance = 100000000000000000000000000; const POOL_ID: PoolId = 12378532; @@ -1048,9 +1048,9 @@ mod tests { pool_id: 1, tranche_id: default_tranche_id(), currency: TOKEN_ID, - price: Rate::one(), + price: Ratio::one(), }, - "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b0000000000000000000000000eb5ec7b00000000033b2e3c9fd0803ce8000000", + "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b0000000000000000000000000eb5ec7b00000000000000000de0b6b3a7640000", ) } @@ -1343,13 +1343,13 @@ mod tests { /// Verify the identity property of decode . encode on a Message value and /// that it in fact encodes to and can be decoded from a given hex string. fn test_encode_decode_identity( - msg: Message, + msg: Message, expected_hex: &str, ) { let encoded = msg.serialize(); assert_eq!(hex::encode(encoded.clone()), expected_hex); - let decoded: Message = Message::deserialize( + let decoded: Message = Message::deserialize( &mut hex::decode(expected_hex) .expect("Decode should work") .as_slice(), diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index e2792b5533..f1bb9af664 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1421,7 +1421,7 @@ impl pallet_liquidity_pools::Config for Runtime { type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; - type BalanceRatio = Quantity; + type BalanceRatio = Ratio; type CurrencyId = CurrencyId; type DomainAccountToAccountId = AccountConverter; type DomainAddressToAccountId = AccountConverter; diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index df719541ce..000ba74f0f 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -469,7 +469,7 @@ impl pallet_liquidity_pools::Config for Runtime { type AdminOrigin = EnsureRootOr; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; - type BalanceRatio = Quantity; + type BalanceRatio = Ratio; type CurrencyId = CurrencyId; type DomainAccountToAccountId = AccountConverter; type DomainAddressToAccountId = AccountConverter; diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index f6905e9f5d..f6ac6e2b6a 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1581,7 +1581,7 @@ impl pallet_liquidity_pools::Config for Runtime { type AdminOrigin = EnsureRoot; type AssetRegistry = OrmlAssetRegistry; type Balance = Balance; - type BalanceRatio = Quantity; + type BalanceRatio = Ratio; type CurrencyId = CurrencyId; type DomainAccountToAccountId = AccountConverter; type DomainAddressToAccountId = AccountConverter; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index ba7f441799..36d5ef05e4 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -1259,7 +1259,7 @@ mod same_currencies { assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), pallet_foreign_investments::Error::::InvestError( - InvestError::Decrease + InvestError::DecreaseTransition ) ); }); @@ -1299,7 +1299,7 @@ mod same_currencies { assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), pallet_foreign_investments::Error::::RedeemError( - RedeemError::Decrease + RedeemError::DecreaseTransition ) ); }); @@ -2255,7 +2255,6 @@ mod mismatching_currencies { .into() })); - // TODO: Check redemption consumes investment instead // Process remaining redemption at 25% rate, i.e. 1 pool currency = // 4 tranche tokens assert_ok!(Investments::process_redeem_orders(default_investment_id())); @@ -2298,7 +2297,8 @@ mod mismatching_currencies { .into() })); - // Redeem again + // Redeem again with goal of redemption swap to foreign consuming investment + // swap to pool let msg = LiquidityPoolMessage::IncreaseRedeemOrder { pool_id, tranche_id: default_tranche_id(pool_id), From 04344029e7d3e949209b52ac788216b9d55ece59 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 13 Sep 2023 17:18:47 +0200 Subject: [PATCH 89/96] refactor: more explicit currency converter --- libs/traits/src/lib.rs | 2 +- .../foreign-investments/src/impls/invest.rs | 2 +- pallets/foreign-investments/src/impls/mod.rs | 2 +- pallets/foreign-investments/src/lib.rs | 8 +- pallets/foreign-investments/src/types.rs | 4 +- runtime/altair/src/lib.rs | 7 +- runtime/centrifuge/src/lib.rs | 7 +- runtime/common/src/lib.rs | 39 ++++----- runtime/development/src/lib.rs | 7 +- .../liquidity_pools/foreign_investments.rs | 86 +++++++++---------- 10 files changed, 74 insertions(+), 90 deletions(-) diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index bc8ced19e8..fdcc122bfb 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -587,7 +587,7 @@ pub trait StatusNotificationHook { /// Trait to synchronously provide a currency conversion estimation for foreign /// currencies into/from pool currencies. -pub trait SimpleCurrencyConversion { +pub trait IdentityCurrencyConversion { type Balance; type Currency; type Error; diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index 30358f1a21..cd198d4f0c 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -13,7 +13,7 @@ use core::cmp::Ordering; -use cfg_traits::SimpleCurrencyConversion; +use cfg_traits::IdentityCurrencyConversion; use cfg_types::investments::Swap; use sp_runtime::{ traits::{EnsureAdd, EnsureSub, Zero}, diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index ef0970c89b..dcb5a8b303 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -14,7 +14,7 @@ use cfg_traits::{ investments::{ForeignInvestment, Investment, InvestmentCollector, TrancheCurrency}, - PoolInspect, SimpleCurrencyConversion, StatusNotificationHook, TokenSwaps, + IdentityCurrencyConversion, PoolInspect, StatusNotificationHook, TokenSwaps, }; use cfg_types::investments::{ CollectedAmount, ExecutedForeignCollectInvest, ExecutedForeignCollectRedeem, diff --git a/pallets/foreign-investments/src/lib.rs b/pallets/foreign-investments/src/lib.rs index 66aca8c74f..04721d6aee 100644 --- a/pallets/foreign-investments/src/lib.rs +++ b/pallets/foreign-investments/src/lib.rs @@ -217,7 +217,13 @@ pub mod pallet { /// Type which provides a conversion from one currency amount to another /// currency amount. - type CurrencyConverter: cfg_traits::SimpleCurrencyConversion< + /// + /// NOTE: Restricting to `IdentityCurrencyConversion` is solely a + /// short-term MVP solution. In the near future, this type must be + /// restricted to a more sophisticated trait which provides + /// unidirectional conversions based on an oracle, dynamic prices or at + /// least conversion ratios based on specific currency pairs. + type CurrencyConverter: cfg_traits::IdentityCurrencyConversion< Balance = Self::Balance, Currency = Self::CurrencyId, Error = DispatchError, diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 9fc39dc0fd..337687893b 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -11,7 +11,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use cfg_traits::SimpleCurrencyConversion; +use cfg_traits::IdentityCurrencyConversion; use cfg_types::investments::Swap; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{dispatch::fmt::Debug, RuntimeDebugNoBound}; @@ -36,7 +36,7 @@ pub enum TokenSwapReason { pub trait InvestStateConfig { type Balance: Clone + Copy + EnsureAdd + EnsureSub + Ord + Debug + Zero; type CurrencyId: Clone + Copy + PartialEq + Debug; - type CurrencyConverter: SimpleCurrencyConversion< + type CurrencyConverter: IdentityCurrencyConversion< Balance = Self::Balance, Currency = Self::CurrencyId, Error = sp_runtime::DispatchError, diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index f1bb9af664..ce2b56ee81 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1390,17 +1390,14 @@ impl pallet_xcm_transactor::Config for Runtime { parameter_types! { pub DefaultTokenSellRate: Ratio = Ratio::one(); - pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CollectedForeignRedemptionHook = pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; - type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< - OrmlAssetRegistry, - StableToStableRatio, - >; + type CurrencyConverter = + runtime_common::foreign_investments::IdentityPoolCurrencyConverter; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 000ba74f0f..1cfc42055d 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -431,17 +431,14 @@ impl orml_asset_registry::Config for Runtime { parameter_types! { pub DefaultTokenSellRate: Ratio = Ratio::one(); - pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CollectedForeignRedemptionHook = pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; - type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< - OrmlAssetRegistry, - StableToStableRatio, - >; + type CurrencyConverter = + runtime_common::foreign_investments::IdentityPoolCurrencyConverter; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index e369361d65..3886440513 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -423,38 +423,33 @@ pub mod xcm_transactor { pub mod foreign_investments { use cfg_primitives::{conversion::convert_balance_decimals, Balance}; - use cfg_traits::SimpleCurrencyConversion; - use cfg_types::{fixed_point::Ratio, tokens::CurrencyId}; + use cfg_traits::IdentityCurrencyConversion; + use cfg_types::tokens::CurrencyId; use frame_support::pallet_prelude::PhantomData; use orml_traits::asset_registry::Inspect; - use sp_runtime::{ - traits::{EnsureFixedPointNumber, Get}, - DispatchError, - }; + use sp_runtime::DispatchError; - /// Simple stable coin amount converter from one stable to another. Provides - /// a synchronous estimation of the amount of one stable currency in - /// another, e.g., the worth of 100 EthWrappedDai in USDC. + /// Simple currency converter which maps the amount of the outgoing currency + /// to the precision of the incoming one. E.g., the worth of 100 + /// EthWrappedDai in USDC. /// - /// For now, converts any `ForeignAsset` into another with the configured - /// rate. + /// Requires currencies to have their decimal precision registered in an + /// asset registry. Moreover, one of the currencies must be a allowed as + /// pool currency. /// - /// NOTE: Should be deprecated ASAP! - // TODO(@review): Can we determine whether a ForeignAsset is a stable coin at - // this point of time? - pub struct SimpleStableCurrencyConverter( - PhantomData<(AssetRegistry, StableToStableRatio)>, - ); - - impl SimpleCurrencyConversion - for SimpleStableCurrencyConverter + /// NOTE: This converter is only supposed to be used short-term as an MVP + /// for stable coin conversions. We assume those conversions to be 1-to-1 + /// bidirectionally. In the near future, this conversion must be improved to + /// account for conversion ratios other than 1.0. + pub struct IdentityPoolCurrencyConverter(PhantomData); + + impl IdentityCurrencyConversion for IdentityPoolCurrencyConverter where AssetRegistry: Inspect< AssetId = CurrencyId, Balance = Balance, CustomMetadata = cfg_types::tokens::CustomMetadata, >, - StableToStableRatio: Get, { type Balance = Balance; type Currency = CurrencyId; @@ -481,7 +476,7 @@ pub mod foreign_investments { convert_balance_decimals( from_metadata.decimals, to_metadata.decimals, - StableToStableRatio::get().ensure_mul_int(amount_out)?, + amount_out, ) .map_err(DispatchError::from) } diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index f6ac6e2b6a..5be43339c3 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1546,17 +1546,14 @@ impl orml_asset_registry::Config for Runtime { parameter_types! { pub DefaultTokenSellRate: Ratio = Ratio::one(); - pub StableToStableRatio: Ratio = Ratio::one(); } impl pallet_foreign_investments::Config for Runtime { type Balance = Balance; type CollectedForeignRedemptionHook = pallet_liquidity_pools::hooks::CollectedForeignRedemptionHook; - type CurrencyConverter = runtime_common::foreign_investments::SimpleStableCurrencyConverter< - OrmlAssetRegistry, - StableToStableRatio, - >; + type CurrencyConverter = + runtime_common::foreign_investments::IdentityPoolCurrencyConverter; type CurrencyId = CurrencyId; type DecreasedForeignInvestOrderHook = pallet_liquidity_pools::hooks::DecreasedForeignInvestOrderHook; diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index 36d5ef05e4..a759a72be3 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -26,7 +26,7 @@ use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, use cfg_traits::{ investments::{Investment, OrderManager, TrancheCurrency as TrancheCurrencyT}, liquidity_pools::InboundQueue, - PoolInspect, SimpleCurrencyConversion, + IdentityCurrencyConversion, PoolInspect, }; use cfg_types::{ domain_address::{Domain, DomainAddress}, @@ -43,7 +43,7 @@ use cfg_types::{ use development_runtime::{ Balances, ForeignInvestments, Investments, LiquidityPools, LocationToAccountId, OrmlAssetRegistry, Permissions, PoolSystem, Runtime as DevelopmentRuntime, RuntimeOrigin, - StableToStableRatio, System, Tokens, + System, Tokens, }; use frame_support::{ assert_noop, assert_ok, @@ -59,7 +59,7 @@ use pallet_foreign_investments::{ }; use pallet_investments::CollectOutcome; use runtime_common::{ - account_conversion::AccountConverter, foreign_investments::SimpleStableCurrencyConverter, + account_conversion::AccountConverter, foreign_investments::IdentityPoolCurrencyConverter, }; use sp_runtime::{ traits::{AccountIdConversion, BadOrigin, ConstU32, Convert, EnsureAdd, One, Zero}, @@ -1259,7 +1259,7 @@ mod same_currencies { assert_noop!( LiquidityPools::submit(DEFAULT_DOMAIN_ADDRESS_MOONBEAM, msg), pallet_foreign_investments::Error::::InvestError( - InvestError::DecreaseTransition + InvestError::DecreaseAmountOverflow ) ); }); @@ -1481,15 +1481,13 @@ mod mismatching_currencies { // USDT investment preparations register_usdt(); - let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRatio, - >::stable_to_stable( - foreign_currency, - pool_currency, - invest_amount_pool_denominated, - ) - .unwrap(); + let invest_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); // Should fail to increase to an invalid payment currency assert!(!ForeignInvestments::accepted_payment_currency( @@ -1681,15 +1679,13 @@ mod mismatching_currencies { &trader, invest_amount_pool_denominated )); - let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRatio, - >::stable_to_stable( - foreign_currency, - pool_currency, - invest_amount_pool_denominated, - ) - .unwrap(); + let invest_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); assert_ok!(OrderBook::add_trading_pair( RuntimeOrigin::root(), pool_currency, @@ -1866,15 +1862,13 @@ mod mismatching_currencies { // USDT setup register_usdt(); enable_liquidity_pool_transferability(foreign_currency); - let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRatio, - >::stable_to_stable( - foreign_currency, - pool_currency, - invest_amount_pool_denominated, - ) - .unwrap(); + let invest_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); assert_ok!(Tokens::mint_into( foreign_currency, &trader, @@ -2108,15 +2102,13 @@ mod mismatching_currencies { // USDT setup register_usdt(); enable_liquidity_pool_transferability(foreign_currency); - let invest_amount_foreign_denominated: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRatio, - >::stable_to_stable( - foreign_currency, - pool_currency, - invest_amount_pool_denominated, - ) - .unwrap(); + let invest_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); assert_ok!(Tokens::mint_into( foreign_currency, &trader, @@ -2504,13 +2496,13 @@ mod setup { .into() })); } else { - let amount_pool_denominated: u128 = SimpleStableCurrencyConverter::< - OrmlAssetRegistry, - StableToStableRatio, - >::stable_to_stable( - pool_currency, currency_id, amount - ) - .unwrap(); + let amount_pool_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + pool_currency, + currency_id, + amount, + ) + .unwrap(); assert_eq!( InvestmentState::::get(&investor, default_investment_id()), InvestState::ActiveSwapIntoPoolCurrency { From d28fd0d9c5eacebedd33f060b77fdf9227ebce75 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 14 Sep 2023 17:52:51 +0200 Subject: [PATCH 90/96] fix: implicit collect on swap fulfillment --- pallets/foreign-investments/src/impls/mod.rs | 8 + .../liquidity_pools/foreign_investments.rs | 272 ++++++++++++++++-- 2 files changed, 258 insertions(+), 22 deletions(-) diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index dcb5a8b303..b2d44a7967 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -778,6 +778,14 @@ impl Pallet { }, ); } + // Edge case: Only occurs as result of implicit collect when fulfilling a swap + // order. At this point, swap is fulfilled but not propagated to the state yet as + // collecting has to happen beforehand. + Some(swap_order_id) + if !T::TokenSwaps::is_active(swap_order_id) && !cancel_swap_order => + { + Self::kill_swap_order(who, investment_id)?; + } // Swap order either has not existed at all or was just cancelled _ => { let swap_order_id = T::TokenSwaps::place_order( diff --git a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs index a759a72be3..40a3f044ab 100644 --- a/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs +++ b/runtime/integration-tests/src/liquidity_pools/pallet/development/tests/liquidity_pools/foreign_investments.rs @@ -1821,13 +1821,6 @@ mod mismatching_currencies { }); } - fn redeem_with_swaps_happy_path() { - // increase - // process - // fulfill swap order - todo!() - } - #[test] /// Verify handling concurrent swap orders works if /// * Invest is swapping from pool to foreign after decreasing an @@ -2072,10 +2065,6 @@ mod mismatching_currencies { }); } - // increase invest --> swap into pool - // - // increase redeem - // process redemption --> swap into foreign #[test] /// Verify handling concurrent swap orders works if /// * Invest is swapping from foreign to pool after increasing @@ -2385,21 +2374,260 @@ mod mismatching_currencies { }); } + /// 1. increase initial invest in pool currency + /// 2. increase invest in foreign + /// 3. process invest + /// 4. fulfill swap order + #[test] fn fulfill_invest_swap_order_requires_collect() { - todo!() - // increase initial invest in pool currency - // increase invest in foreign - // process invest - // fulfill swap order + TestNet::reset(); + Development::execute_with(|| { + // Increase invest setup + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); + let trader: AccountId = ALICE.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let invest_amount_pool_denominated: u128 = 10_000_000_000_000_000; + let swap_order_id = 1; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + // invest in pool currency to reach `InvestmentOngoing` quickly + do_initial_increase_investment( + pool_id, + invest_amount_pool_denominated, + investor.clone(), + pool_currency, + ); + + // USDT setup + register_usdt(); + enable_liquidity_pool_transferability(foreign_currency); + let invest_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + invest_amount_pool_denominated, + ) + .unwrap(); + assert_ok!(Tokens::mint_into( + pool_currency, + &trader, + invest_amount_pool_denominated + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + pool_currency, + foreign_currency, + 1 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + foreign_currency, + pool_currency, + 1 + )); + + // Increase invest have + // InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing + let msg = LiquidityPoolMessage::IncreaseInvestOrder { + pool_id, + tranche_id: default_tranche_id(pool_id), + investor: investor.clone().into(), + currency: general_currency_index(foreign_currency), + amount: invest_amount_foreign_denominated, + }; + assert_ok!(LiquidityPools::submit( + DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + msg.clone() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::ActiveSwapIntoPoolCurrencyAndInvestmentOngoing { + swap: Swap { + amount: invest_amount_pool_denominated, + currency_in: pool_currency, + currency_out: foreign_currency, + }, + invest_amount: invest_amount_pool_denominated + } + ); + // Process 50% of investment at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::process_invest_orders(default_investment_id())); + assert_ok!(Investments::invest_fulfillment( + default_investment_id(), + FulfillmentWithPrice { + of_amount: Perquintill::from_percent(50), + price: Quantity::checked_from_rational(1, 4).unwrap(), + } + )); + assert!(Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + + // Fulfill swap order should implicitly collect, otherwise the unprocessed + // investment amount is unknown + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(!Investments::investment_requires_collect( + &investor, + default_investment_id() + )); + assert_eq!( + InvestmentState::::get(&investor, default_investment_id()), + InvestState::InvestmentOngoing { + invest_amount: invest_amount_pool_denominated / 2 * 3 + } + ); + }); } + /// 1. increase initial redeem + /// 2. process partial redemption + /// 3. collect + /// 4. process redemption + /// 5. fulfill swap order should implicitly collect + #[test] fn fulfill_redeem_swap_order_requires_collect() { - // increase initial redeem - // process redemption - // collect partial - // collect partial - // fulfill swap order - todo!() + TestNet::reset(); + Development::execute_with(|| { + // Increase redeem setup + setup_pre_requirements(); + let pool_id = DEFAULT_POOL_ID; + let investor: AccountId = + AccountConverter::::convert(( + DOMAIN_MOONBEAM, + BOB, + )); + let trader: AccountId = ALICE.into(); + let pool_currency: CurrencyId = AUSD_CURRENCY_ID; + let foreign_currency: CurrencyId = USDT_CURRENCY_ID; + let pool_currency_decimals = currency_decimals::AUSD; + let redeem_amount_pool_denominated: u128 = 10_000_000_000_000_000; + let swap_order_id = 1; + create_currency_pool(pool_id, pool_currency, pool_currency_decimals.into()); + let pool_account = + pallet_pool_system::pool_types::PoolLocator { pool_id }.into_account_truncating(); + assert_ok!(Tokens::mint_into( + pool_currency, + &pool_account, + redeem_amount_pool_denominated + )); + + // USDT setup + register_usdt(); + enable_liquidity_pool_transferability(foreign_currency); + let redeem_amount_foreign_denominated: u128 = + IdentityPoolCurrencyConverter::::stable_to_stable( + foreign_currency, + pool_currency, + redeem_amount_pool_denominated, + ) + .unwrap(); + assert_ok!(Tokens::mint_into( + foreign_currency, + &trader, + redeem_amount_foreign_denominated + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + pool_currency, + foreign_currency, + 1 + )); + assert_ok!(OrderBook::add_trading_pair( + RuntimeOrigin::root(), + foreign_currency, + pool_currency, + 1 + )); + + do_initial_increase_redemption( + pool_id, + redeem_amount_pool_denominated, + investor.clone(), + foreign_currency, + ); + + // Process 50% of redemption at 50% rate, i.e. 1 pool currency = 2 tranche + // tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice { + of_amount: Perquintill::from_percent(50), + price: Quantity::checked_from_rational(1, 2).unwrap(), + } + )); + assert_noop!( + OrderBook::fill_order_full(RuntimeOrigin::signed(trader.clone()), swap_order_id), + pallet_order_book::Error::::OrderNotFound + ); + assert!(Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + assert_ok!(Investments::collect_redemptions_for( + RuntimeOrigin::signed(CHARLIE.into()), + investor.clone(), + default_investment_id() + )); + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::RedeemingAndActiveSwapIntoForeignCurrency { + redeem_amount: redeem_amount_pool_denominated / 2, + swap: Swap { + amount: redeem_amount_foreign_denominated / 4, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + + // Process remaining redemption at 25% rate, i.e. 1 pool currency = 4 tranche + // tokens + assert_ok!(Investments::process_redeem_orders(default_investment_id())); + assert_ok!(Investments::redeem_fulfillment( + default_investment_id(), + FulfillmentWithPrice { + of_amount: Perquintill::from_percent(100), + price: Quantity::checked_from_rational(1, 4).unwrap(), + } + )); + assert!(Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + assert_ok!(OrderBook::fill_order_full( + RuntimeOrigin::signed(trader.clone()), + swap_order_id + )); + assert!(!Investments::redemption_requires_collect( + &investor, + default_investment_id() + )); + // TODO: Assert ExecutedCollectRedeem was not dispatched + assert_eq!( + RedemptionState::::get(&investor, default_investment_id()), + RedeemState::ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDone { + done_amount: redeem_amount_foreign_denominated / 4, + swap: Swap { + amount: redeem_amount_foreign_denominated / 8, + currency_in: foreign_currency, + currency_out: pool_currency + } + } + ); + }); } } From 28e11464ca111a10be49c82d9fbb12f2ce5319e1 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 12:47:48 +0200 Subject: [PATCH 91/96] refactor: improvements --- pallets/foreign-investments/src/hooks.rs | 2 ++ .../foreign-investments/src/impls/invest.rs | 2 +- pallets/foreign-investments/src/impls/mod.rs | 1 + pallets/foreign-investments/src/types.rs | 36 +++++++++++-------- pallets/order-book/src/lib.rs | 2 -- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/pallets/foreign-investments/src/hooks.rs b/pallets/foreign-investments/src/hooks.rs index 28dda93e7b..f5b0e9dba6 100644 --- a/pallets/foreign-investments/src/hooks.rs +++ b/pallets/foreign-investments/src/hooks.rs @@ -106,6 +106,7 @@ impl FulfilledSwapOrderHook { /// NOTE: If the transition should be followed by a `RedeemState` /// transition, the `update_swap_order` should be set to false in order to /// oppress updating the swap order here. + #[transactional] fn fulfill_invest_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, @@ -142,6 +143,7 @@ impl FulfilledSwapOrderHook { } /// Transitions the `RedeemState` after fulfilling a swap order. + #[transactional] fn fulfill_redeem_swap_order( who: &T::AccountId, investment_id: T::InvestmentId, diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index cd198d4f0c..b45857c6ba 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -815,7 +815,7 @@ where swap: Swap { amount: pool_swap.amount.ensure_sub(swap.amount)?, ..swap - }, + }, invest_amount, }), // should never occur but let's be safe here diff --git a/pallets/foreign-investments/src/impls/mod.rs b/pallets/foreign-investments/src/impls/mod.rs index b2d44a7967..4b82327e70 100644 --- a/pallets/foreign-investments/src/impls/mod.rs +++ b/pallets/foreign-investments/src/impls/mod.rs @@ -709,6 +709,7 @@ impl Pallet { /// Kills all storage associated with token swaps and cancels the /// potentially active swap order. + #[transactional] fn kill_swap_order(who: &T::AccountId, investment_id: T::InvestmentId) -> DispatchResult { if let Some(swap_order_id) = TokenSwapOrderIds::::take(who, investment_id) { if T::TokenSwaps::is_active(swap_order_id) { diff --git a/pallets/foreign-investments/src/types.rs b/pallets/foreign-investments/src/types.rs index 337687893b..4b2de308c1 100644 --- a/pallets/foreign-investments/src/types.rs +++ b/pallets/foreign-investments/src/types.rs @@ -94,9 +94,9 @@ pub enum InvestState { /// * The remainder was swapped back into the foreign currency as a result /// of decreasing the invested amount before being processed. /// - /// NOTE: This state can be transitioned into `ActiveSwapIntoPoolCurrency` - /// by applying the corresponding trigger to handle the foreign return - /// amount. + /// NOTE: This state is transitioned into `ActiveSwapIntoPoolCurrency` + /// in the post-processing `apply_invest_state_transition` as the done part + /// invokes `ExecutedDecreaseInvestOrder` dispatch. ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDone { swap: Swap, done_amount: T::Balance, @@ -113,9 +113,10 @@ pub enum InvestState { /// * The remainder was swapped back into the foreign currency as a result /// of decreasing the invested amount before being processed. /// - /// NOTE: This state can be transitioned into - /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` by applying the - /// corresponding trigger to handle the foreign return amount. + /// NOTE: This state is transitioned into + /// `ActiveSwapIntoPoolCurrencyAndInvestmentOngoing` in the post-processing + /// `apply_invest_state_transition` as the done part invokes + /// `ExecutedDecreaseInvestOrder` dispatch. ActiveSwapIntoPoolCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap, done_amount: T::Balance, @@ -127,7 +128,7 @@ pub enum InvestState { /// decreasing the invested amount before being processed. /// * The remainder was already swapped back into the foreign currency. /// - /// NOTE: This state should not be transitioned by applying the trigger for + /// NOTE: This state must not be transitioned by applying the trigger for /// the done part but wait until the active swap is fulfilled. ActiveSwapIntoForeignCurrencyAndSwapIntoForeignDoneAndInvestmentOngoing { swap: Swap, @@ -136,8 +137,9 @@ pub enum InvestState { }, /// The unprocessed investment was swapped back into foreign currency. /// - /// NOTE: This state can be killed by applying the corresponding trigger to - /// handle the foreign return amount. + /// NOTE: This state is killed in the post-processing + /// `apply_invest_state_transition` as it invokes + /// `ExecutedDecreaseInvestOrder` dispatch. SwapIntoForeignDone { done_swap: Swap, }, @@ -146,8 +148,9 @@ pub enum InvestState { /// * The swapped back into the foreign currency as a result of decreasing /// the invested amount before being processed. /// - /// NOTE: This state can be transitioned into `InvestmentOngoing` by - /// applying the corresponding trigger to handle the foreign return amount. + /// NOTE: This state is transitioned into `InvestmentOngoing` in the + /// post-processing `apply_invest_state_transition` as the done part invokes + /// `ExecutedDecreaseInvestOrder` dispatch. SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap, invest_amount: T::Balance, @@ -307,9 +310,9 @@ pub enum RedeemState< /// The redemption was fully processed, collected and swapped into the /// foreign currency. /// - /// NOTE: This state does not require handling in `RedeemState::transition` - /// as it must be manually transitioned in `apply_redeem_state_transition`, - /// similar to the corresponding state in `InvestState`. + /// NOTE: This state is automatically killed in the post-processing + /// `apply_collect_redeem_transition` as it prepares the dispatch of + /// `ExecutedCollectRedeem` message which needs to be triggered manually. SwapIntoForeignDone { done_swap: Swap }, /// The redemption is split into two parts: /// * One part is waiting to be processed as redemption. @@ -323,6 +326,11 @@ pub enum RedeemState< /// * One part is waiting to be processed as redemption. /// * The remainder is swapping back into the foreign currency as a result /// of processing and collecting beforehand. + /// + /// NOTE: This state is automatically transitioned into `Redeeming` in the + /// post-processing `apply_collect_redeem_transition` as the done part + /// prepares the dispatch of `ExecutedCollectRedeem` message which needs to + /// be triggered manually. RedeemingAndSwapIntoForeignDone { redeem_amount: Balance, done_swap: Swap, diff --git a/pallets/order-book/src/lib.rs b/pallets/order-book/src/lib.rs index aec43dbf3c..1b97fe1c57 100644 --- a/pallets/order-book/src/lib.rs +++ b/pallets/order-book/src/lib.rs @@ -634,8 +634,6 @@ pub mod pallet { .ok_or(Error::::InvalidAssetId)? .decimals; - // FIXME: Maybe. This equals 10^(to - from) * to_amount when it should be - // multiplied with from_amount? Or convert_balance_decimals(from_decimals, to_decimals, ratio.ensure_mul_int(amount)?) .map_err(DispatchError::from) } From 65c285b2ae500ecf64bceac7405227fc0c010010 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 14:44:57 +0200 Subject: [PATCH 92/96] feat: stump queue altair, centrifuge; inbound queue algol --- runtime/altair/src/lib.rs | 37 +++++------------------------ runtime/centrifuge/src/lib.rs | 35 ++++------------------------ runtime/common/src/gateway.rs | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 61 deletions(-) diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index ce2b56ee81..5324fc4543 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1443,37 +1443,13 @@ parameter_types! { pub Sender: AccountId = GatewayAccountProvider::::get_gateway_account(); } -/// A -pub struct StumbInboundQueue; -impl InboundQueue for StumbInboundQueue { - type Message = pallet_liquidity_pools::Message; - type Sender = DomainAddress; - - fn submit(sender: Self::Sender, message: Self::Message) -> DispatchResult { - let event = { - let event = - pallet_liquidity_pools::Event::::IncomingMessage { sender, message }; - - // Mirror deposit_event logic here as it is private - let event = <::RuntimeEvent as From< - pallet_liquidity_pools::Event, - >>::from(event); - - <::RuntimeEvent as Into< - ::RuntimeEvent, - >>::into(event) - }; - - // Triggering only the event for error resolution - System::deposit_event(event); - - Ok(()) - } -} - impl pallet_liquidity_pools_gateway::Config for Runtime { type AdminOrigin = EnsureRootOr; - type InboundQueue = StumbInboundQueue; + #[cfg(not(feature = "testnet-runtime"))] + type InboundQueue = + runtime_common::gateway::stump_queue::StumpInboundQueue; + #[cfg(feature = "testnet-runtime")] + type InboundQueue = LiquidityPools; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; type Message = pallet_liquidity_pools::Message; @@ -2056,8 +2032,7 @@ mod __runtime_api_use { #[cfg(not(feature = "disable-runtime-api"))] use __runtime_api_use::*; -use cfg_traits::liquidity_pools::InboundQueue; -use cfg_types::domain_address::{Domain, DomainAddress}; +use cfg_types::domain_address::Domain; use runtime_common::{account_conversion::AccountConverter, xcm::AccountIdToMultiLocation}; #[cfg(not(feature = "disable-runtime-api"))] diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 1cfc42055d..2755f2beda 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -22,13 +22,12 @@ pub use cfg_primitives::{constants::*, types::*}; use cfg_traits::{ investments::{OrderManager, TrancheCurrency as _}, - liquidity_pools::{InboundQueue, OutboundQueue}, - Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, StatusNotificationHook, - TryConvert, + liquidity_pools::OutboundQueue, + Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, TryConvert, }; use cfg_types::{ consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes}, - domain_address::{Domain, DomainAddress}, + domain_address::Domain, fee_keys::FeeKey, fixed_point::{Quantity, Rate, Ratio}, ids::PRICE_ORACLE_PALLET_ID, @@ -539,7 +538,8 @@ parameter_types! { impl pallet_liquidity_pools_gateway::Config for Runtime { type AdminOrigin = EnsureAccountOrRootOr; - type InboundQueue = DummyInboundQueue; + type InboundQueue = + runtime_common::gateway::stump_queue::StumpInboundQueue; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; type Message = LiquidityPoolsMessage; @@ -551,19 +551,6 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type WeightInfo = (); } -/// DummyInboundQueue will be used in the first phase of testing in order to -/// ensure that no incoming messages will be processed. -pub struct DummyInboundQueue; - -impl InboundQueue for DummyInboundQueue { - type Message = LiquidityPoolsMessage; - type Sender = DomainAddress; - - fn submit(_: Self::Sender, _: Self::Message) -> DispatchResult { - Err(DispatchError::Other("InboundQueue not supported yet")) - } -} - impl pallet_randomness_collective_flip::Config for Runtime {} impl parachain_info::Config for Runtime {} @@ -1770,18 +1757,6 @@ impl< } } -// TODO: Remove when adding pallet_foreign_investments to runtime -pub struct NoopCollectHook; -impl StatusNotificationHook for NoopCollectHook { - type Error = DispatchError; - type Id = cfg_types::investments::ForeignInvestmentInfo; - type Status = cfg_types::investments::CollectedAmount; - - fn notify_status_change(_id: Self::Id, _status: Self::Status) -> DispatchResult { - Ok(()) - } -} - impl pallet_investments::Config for Runtime { type Accountant = PoolSystem; type Amount = Balance; diff --git a/runtime/common/src/gateway.rs b/runtime/common/src/gateway.rs index b82249b63a..0e03ca623b 100644 --- a/runtime/common/src/gateway.rs +++ b/runtime/common/src/gateway.rs @@ -35,3 +35,47 @@ where AccountConverter::::into_account_id(truncated_sender_account) } } + +// NOTE: Can be removed once all runtimes implement a true InboundQueue +pub mod stump_queue { + use cfg_traits::liquidity_pools::InboundQueue; + use cfg_types::domain_address::{Domain, DomainAddress}; + use sp_runtime::DispatchResult; + use sp_std::marker::PhantomData; + + pub struct StumpInboundQueue(PhantomData<(Runtime, RuntimeEvent)>); + impl InboundQueue for StumpInboundQueue + where + Runtime: pallet_liquidity_pools::Config + frame_system::Config, + { + type Message = pallet_liquidity_pools::Message< + Domain, + ::PoolId, + ::TrancheId, + ::Balance, + ::BalanceRatio, + >; + type Sender = DomainAddress; + + fn submit(sender: Self::Sender, message: Self::Message) -> DispatchResult { + let event = { + let event = + pallet_liquidity_pools::Event::::IncomingMessage { sender, message }; + + // Mirror deposit_event logic here as it is private + let event = <::RuntimeEvent as From< + pallet_liquidity_pools::Event, + >>::from(event); + + <::RuntimeEvent as Into< + ::RuntimeEvent, + >>::into(event) + }; + + // Triggering only the event for error resolution + frame_system::pallet::Pallet::::deposit_event(event); + + Ok(()) + } + } +} From ffea07f5cb06fed289f67e840dae4bf573b765c5 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 14:57:54 +0200 Subject: [PATCH 93/96] refactor: stricter fulfill invest swap order --- .../foreign-investments/src/impls/invest.rs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pallets/foreign-investments/src/impls/invest.rs b/pallets/foreign-investments/src/impls/invest.rs index b45857c6ba..4c3a98a6eb 100644 --- a/pallets/foreign-investments/src/impls/invest.rs +++ b/pallets/foreign-investments/src/impls/invest.rs @@ -827,8 +827,7 @@ where swap.ensure_currencies_match(foreign_swap, true)?; match swap.amount.cmp(&foreign_swap.amount) { - // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign - Ordering::Equal | Ordering::Greater => { + Ordering::Equal => { Ok(Self::SwapIntoForeignDone { done_swap: swap }) } Ordering::Less => { @@ -839,8 +838,8 @@ where }, done_amount: swap.amount, }) - } - } + }, + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), } }, // Increment done_foreign by swapped amount, leave invest amount untouched Self::ActiveSwapIntoForeignCurrencyAndInvestmentOngoing { @@ -850,8 +849,7 @@ where swap.ensure_currencies_match(foreign_swap, true)?; match swap.amount.cmp(&foreign_swap.amount) { - // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign - Ordering::Equal | Ordering::Greater => { + Ordering::Equal => { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: swap, invest_amount: *invest_amount, @@ -868,7 +866,8 @@ where invest_amount: *invest_amount, }, ) - } + }, + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), } }, // Increment done_foreign by swapped amount @@ -880,8 +879,7 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; match swap.amount.cmp(&foreign_swap.amount) { - // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign - Ordering::Equal | Ordering::Greater => { + Ordering::Equal => { Ok(Self::SwapIntoForeignDone { done_swap: Swap { amount: done_amount, @@ -897,7 +895,8 @@ where }, done_amount, }) - } + }, + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), } }, // Increment done_foreign by swapped amount, leave invest amount untouched @@ -910,8 +909,7 @@ where let done_amount = done_amount.ensure_add(swap.amount)?; match swap.amount.cmp(&foreign_swap.amount) { - // Allowing geq here for handling fulfillment of concurrent active invest and redeem swaps into foreign - Ordering::Equal | Ordering::Greater => { + Ordering::Equal => { Ok(Self::SwapIntoForeignDoneAndInvestmentOngoing { done_swap: Swap { amount: done_amount, @@ -931,7 +929,8 @@ where invest_amount: *invest_amount, }, ) - } + }, + Ordering::Greater => Err(DispatchError::Arithmetic(ArithmeticError::Overflow)), } }, _ => Err(DispatchError::Other( From 181898195dfe90d4f6e1843afe6734c0cb1215ba Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 16:06:59 +0200 Subject: [PATCH 94/96] refactor: apply AllowInvestmentCurrency --- pallets/liquidity-pools/src/lib.rs | 2 +- pallets/liquidity-pools/src/message.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 39ff697fe4..4ee732d2b8 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -714,7 +714,7 @@ pub mod pallet { T::OutboundQueue::submit( who, Domain::EVM(chain_id), - Message::AllowPoolCurrency { pool_id, currency }, + Message::AllowInvestmentCurrency { pool_id, currency }, )?; Ok(()) diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 693481cb88..ceb93cf327 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -56,7 +56,7 @@ where /// Allow a currency to be used as a pool currency and to invest in a pool. /// /// Directionality: Centrifuge -> EVM Domain. - AllowPoolCurrency { + AllowInvestmentCurrency { pool_id: PoolId, currency: u128, }, @@ -388,7 +388,7 @@ impl< Self::Invalid { .. } => 0, Self::AddCurrency { .. } => 1, Self::AddPool { .. } => 2, - Self::AllowPoolCurrency { .. } => 3, + Self::AllowInvestmentCurrency { .. } => 3, Self::AddTranche { .. } => 4, Self::UpdateTrancheTokenPrice { .. } => 5, Self::UpdateMember { .. } => 6, @@ -435,7 +435,7 @@ impl< Message::AddPool { pool_id } => { encoded_message(self.call_type(), vec![encode_be(pool_id)]) } - Message::AllowPoolCurrency { pool_id, currency } => encoded_message( + Message::AllowInvestmentCurrency { pool_id, currency } => encoded_message( self.call_type(), vec![encode_be(pool_id), encode_be(currency)], ), @@ -754,7 +754,7 @@ impl< 2 => Ok(Self::AddPool { pool_id: decode_be_bytes::<8, _, _>(input)?, }), - 3 => Ok(Self::AllowPoolCurrency { + 3 => Ok(Self::AllowInvestmentCurrency { pool_id: decode_be_bytes::<8, _, _>(input)?, currency: decode_be_bytes::<16, _, _>(input)?, }), @@ -1008,7 +1008,7 @@ mod tests { #[test] fn allow_pool_currency() { test_encode_decode_identity( - LiquidityPoolsMessage::AllowPoolCurrency { + LiquidityPoolsMessage::AllowInvestmentCurrency { currency: TOKEN_ID, pool_id: POOL_ID, }, @@ -1019,7 +1019,7 @@ mod tests { #[test] fn allow_pool_currency_zero() { test_encode_decode_identity( - LiquidityPoolsMessage::AllowPoolCurrency { + LiquidityPoolsMessage::AllowInvestmentCurrency { currency: 0, pool_id: 0, }, From 04023278217aabbe3a89a1533909add7219acee0 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 16:20:03 +0200 Subject: [PATCH 95/96] chore: bump dev spec_version --- Cargo.lock | 2 +- runtime/development/Cargo.toml | 2 +- runtime/development/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d148fbf77f..f9973a8402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2688,7 +2688,7 @@ dependencies = [ [[package]] name = "development-runtime" -version = "0.10.27" +version = "0.10.29" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index 8992704d7e..acecc2bce2 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "development-runtime" -version = "0.10.27" +version = "0.10.29" authors = ["Centrifuge "] edition = "2021" build = "build.rs" diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 9cfbbe2847..650a1b04ff 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -138,7 +138,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1027, + spec_version: 1029, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, From b4877bb403e3c9d2cae8f9932c93daac4246358b Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 15 Sep 2023 16:21:25 +0200 Subject: [PATCH 96/96] chore: bump altair spec version to 1034 --- Cargo.lock | 2 +- runtime/altair/Cargo.toml | 2 +- runtime/altair/src/lib.rs | 4 ++-- runtime/altair/src/migrations.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9973a8402..7de7d938f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,7 +190,7 @@ dependencies = [ [[package]] name = "altair-runtime" -version = "0.10.33" +version = "0.10.34" dependencies = [ "axelar-gateway-precompile", "cfg-primitives", diff --git a/runtime/altair/Cargo.toml b/runtime/altair/Cargo.toml index ce1c67919d..a7273f69d3 100644 --- a/runtime/altair/Cargo.toml +++ b/runtime/altair/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "altair-runtime" -version = "0.10.33" +version = "0.10.34" authors = ["Centrifuge "] edition = "2021" build = "build.rs" diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index dd17f5c9d7..c6ac5c4300 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -127,7 +127,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("altair"), impl_name: create_runtime_str!("altair"), authoring_version: 1, - spec_version: 1033, + spec_version: 1034, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1918,7 +1918,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - migrations::UpgradeAltair1033, + migrations::UpgradeAltair1034, >; impl fp_self_contained::SelfContainedCall for RuntimeCall { diff --git a/runtime/altair/src/migrations.rs b/runtime/altair/src/migrations.rs index 09d74382c5..f1d3a1f8fd 100644 --- a/runtime/altair/src/migrations.rs +++ b/runtime/altair/src/migrations.rs @@ -15,7 +15,7 @@ use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; /// that have to be applied on that chain, which includes migrations that have /// already been executed on Algol (1028 & 1029). #[cfg(not(feature = "testnet-runtime"))] -pub type UpgradeAltair1033 = ( +pub type UpgradeAltair1034 = ( // FIXME: This migration fails to decode 4 entries against Altair // orml_tokens_migration::CurrencyIdRefactorMigration, // At minimum, bumps storage version from 1 to 2 @@ -57,7 +57,7 @@ pub type UpgradeAltair1033 = ( /// the side releases that only landed on Algol (1028 to 1031) but not yet on /// Altair. #[cfg(feature = "testnet-runtime")] -pub type UpgradeAltair1033 = (); +pub type UpgradeAltair1034 = (); mod asset_registry { use cfg_primitives::Balance;