diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 1c57653272..391f7c55f4 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -114,8 +114,16 @@ pub trait PoolNAV { /// A trait that support pool inspection operations such as pool existence checks and pool admin of permission set. pub trait PoolInspect { - type PoolId: Parameter + Member + Debug + Copy + Default + TypeInfo + Encode + Decode; - type TrancheId: Parameter + Member + Debug + Copy + Default + TypeInfo; + type PoolId: Parameter + + Member + + Debug + + Copy + + Default + + TypeInfo + + Encode + + Decode + + MaxEncodedLen; + type TrancheId: Parameter + Member + Debug + Copy + Default + TypeInfo + MaxEncodedLen; type Rate; type Moment; @@ -145,7 +153,7 @@ pub trait PoolMutate { type MaxTokenSymbolLength: Get; type MaxTranches: Get; type TrancheInput: Encode + Decode + Clone + TypeInfo + Debug + PartialEq; - type PoolChanges: Encode + Decode + Clone + TypeInfo + Debug + PartialEq; + type PoolChanges: Encode + Decode + Clone + TypeInfo + Debug + PartialEq + MaxEncodedLen; fn create( admin: AccountId, diff --git a/libs/types/src/epoch.rs b/libs/types/src/epoch.rs index 7ec3e2f69b..059c96ba63 100644 --- a/libs/types/src/epoch.rs +++ b/libs/types/src/epoch.rs @@ -11,11 +11,11 @@ // GNU General Public License for more details. use cfg_primitives::Moment; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct EpochState { /// Current epoch that is ongoing. pub current: EpochId, diff --git a/libs/types/src/fee_keys.rs b/libs/types/src/fee_keys.rs index b1c8294bb3..def3c0bb53 100644 --- a/libs/types/src/fee_keys.rs +++ b/libs/types/src/fee_keys.rs @@ -10,7 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -19,7 +19,7 @@ use sp_std::cmp::PartialEq; /// Different fees keys available. /// Each variant represents a balance previously determined and configured. -#[derive(Encode, Decode, Clone, Copy, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum FeeKey { /// Key to identify the balance reserved for the author. diff --git a/libs/types/src/fixed_point.rs b/libs/types/src/fixed_point.rs index cd57d82fea..5362b34c73 100644 --- a/libs/types/src/fixed_point.rs +++ b/libs/types/src/fixed_point.rs @@ -18,7 +18,7 @@ //! Decimal Fixed Point implementations for Substrate runtime. //! Copied over from sp_arithmetic -use codec::{CompactAs, Decode, Encode}; +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_arithmetic::{ @@ -430,6 +430,7 @@ pub trait FixedPointNumberExtension: FixedPointNumber { PartialOrd, Ord, scale_info::TypeInfo, + MaxEncodedLen, )] pub struct Rate(u128); diff --git a/libs/types/src/orders.rs b/libs/types/src/orders.rs index 87374624b1..d206332d28 100644 --- a/libs/types/src/orders.rs +++ b/libs/types/src/orders.rs @@ -21,7 +21,7 @@ use sp_std::{ vec::Vec, }; -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct FulfillmentWithPrice { pub of_amount: Perquintill, pub price: BalanceRatio, diff --git a/libs/types/src/permissions.rs b/libs/types/src/permissions.rs index 755e44b45a..8b398044ae 100644 --- a/libs/types/src/permissions.rs +++ b/libs/types/src/permissions.rs @@ -11,10 +11,11 @@ // GNU General Public License for more details. use cfg_traits::Properties; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ sp_runtime::traits::Saturating, traits::{Get, UnixTime}, + BoundedVec, }; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -22,7 +23,6 @@ use serde::{Deserialize, Serialize}; use sp_std::{ cmp::{Ord, PartialEq, PartialOrd}, marker::PhantomData, - vec::Vec, }; /// PoolRole can hold any type of role specific functions a user can do on a given pool. @@ -64,7 +64,7 @@ pub enum Role { PermissionedCurrencyRole(PermissionedCurrencyRole), } -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, TypeInfo, Debug)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, TypeInfo, Debug, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum PermissionScope { Pool(PoolId), @@ -85,7 +85,7 @@ where bitflags::bitflags! { /// The current admin roles we support - #[derive(codec::Encode, codec::Decode, TypeInfo)] + #[derive(codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen)] pub struct PoolAdminRoles: u32 { const POOL_ADMIN = 0b00000001; const BORROWER = 0b00000010; @@ -96,44 +96,44 @@ bitflags::bitflags! { } /// The current admin roles we support - #[derive(codec::Encode, codec::Decode, TypeInfo)] + #[derive(codec::Encode, codec::Decode, TypeInfo, MaxEncodedLen)] pub struct CurrencyAdminRoles: u32 { const PERMISSIONED_ASSET_MANAGER = 0b00000001; const PERMISSIONED_ASSET_ISSUER = 0b00000010; } } -#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen)] pub struct PermissionedCurrencyHolderInfo { permissioned_till: Moment, } -#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen)] pub struct TrancheInvestorInfo { tranche_id: TrancheId, permissioned_till: Moment, } -#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen)] pub struct PermissionedCurrencyHolders { info: Option>, _phantom: PhantomData<(Now, MinDelay)>, } -#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq)] -pub struct TrancheInvestors { - info: Vec>, +#[derive(Encode, Decode, TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen)] +pub struct TrancheInvestors> { + info: BoundedVec, MaxTranches>, _phantom: PhantomData<(Now, MinDelay)>, } /// The structure that we store in the pallet-permissions storage /// This here implements trait Properties. -#[derive(Encode, Decode, TypeInfo, Clone, Eq, PartialEq, Debug)] -pub struct PermissionRoles { +#[derive(Encode, Decode, TypeInfo, Clone, Eq, PartialEq, Debug, MaxEncodedLen)] +pub struct PermissionRoles, Moment = u64> { pool_admin: PoolAdminRoles, currency_admin: CurrencyAdminRoles, permissioned_asset_holder: PermissionedCurrencyHolders, - tranche_investor: TrancheInvestors, + tranche_investor: TrancheInvestors, } impl Default for PermissionedCurrencyHolders @@ -150,28 +150,31 @@ where } } -impl Default - for TrancheInvestors +impl Default + for TrancheInvestors where Now: UnixTime, MinDelay: Get, Moment: From + PartialEq + PartialOrd + Saturating + Ord, TrancheId: PartialEq + PartialOrd, + MaxTranches: Get, { fn default() -> Self { Self { - info: Vec::default(), + info: BoundedVec::default(), _phantom: Default::default(), } } } -impl Default for PermissionRoles +impl Default + for PermissionRoles where Now: UnixTime, MinDelay: Get, Moment: From + PartialEq + PartialOrd + Saturating + Ord, TrancheId: PartialEq + PartialOrd, + MaxTranches: Get, { fn default() -> Self { Self { @@ -179,7 +182,8 @@ where currency_admin: CurrencyAdminRoles::empty(), permissioned_asset_holder: PermissionedCurrencyHolders::::default(), - tranche_investor: TrancheInvestors::::default(), + tranche_investor: + TrancheInvestors::::default(), } } } @@ -189,13 +193,14 @@ where /// This UNION shall reflect that and explain to the reader why it is passed here. pub const UNION: u64 = 0; -impl Properties - for PermissionRoles +impl Properties + for PermissionRoles where Now: UnixTime, MinDelay: Get, Moment: From + PartialEq + PartialOrd + Saturating + Ord + Copy, TrancheId: PartialEq + PartialOrd, + MaxTranches: Get, { type Error = (); type Ok = (); @@ -373,12 +378,14 @@ where } } -impl TrancheInvestors +impl + TrancheInvestors where Now: UnixTime, MinDelay: Get, Moment: From + PartialEq + PartialOrd + Saturating + Ord + Copy, TrancheId: PartialEq + PartialOrd, + MaxTranches: Get, { pub fn empty() -> Self { Self::default() @@ -435,10 +442,12 @@ where Ok(self.info[index].permissioned_till = validity) } } else { - Ok(self.info.push(TrancheInvestorInfo { - tranche_id: tranche, - permissioned_till: validity, - })) + self.info + .try_push(TrancheInvestorInfo { + tranche_id: tranche, + permissioned_till: validity, + }) + .map_err(|_| ()) } } } @@ -454,6 +463,7 @@ mod tests { parameter_types! { pub const MinDelay: u64 = 4; + pub const MaxTranches: u32 = 5; } struct Now(core::time::Duration); @@ -490,9 +500,9 @@ mod tests { #[test] fn permission_roles_work() { - assert!(PermissionRoles::::default().empty()); + assert!(PermissionRoles::::default().empty()); - let mut roles = PermissionRoles::::default(); + let mut roles = PermissionRoles::::default(); // Updating works only when increasing permissions assert!(roles diff --git a/pallets/anchors/src/lib.rs b/pallets/anchors/src/lib.rs index 80d7acd97c..afc5486ae2 100644 --- a/pallets/anchors/src/lib.rs +++ b/pallets/anchors/src/lib.rs @@ -19,7 +19,7 @@ #![allow(clippy::all)] use cfg_traits::fees::{Fee, Fees}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, storage::child, @@ -81,7 +81,7 @@ const ANCHOR_PREFIX: &[u8; 6] = b"anchor"; const EVICT_PRE_COMMIT_LIST_SIZE: u32 = 100; /// The data structure for storing pre-committed anchors. -#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub struct PreCommitData { signing_root: Hash, @@ -112,7 +112,6 @@ pub mod pallet { // method. #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/pallets/bridge/src/lib.rs b/pallets/bridge/src/lib.rs index 30e390804e..c54f62b7ec 100644 --- a/pallets/bridge/src/lib.rs +++ b/pallets/bridge/src/lib.rs @@ -77,7 +77,6 @@ pub mod pallet { // for the pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); // ------------------------------------------------------------------------ diff --git a/pallets/claims/src/lib.rs b/pallets/claims/src/lib.rs index 8288c252e8..3111a78497 100644 --- a/pallets/claims/src/lib.rs +++ b/pallets/claims/src/lib.rs @@ -156,7 +156,6 @@ pub mod pallet { // for the pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); // ------------------------------------------------------------------------ diff --git a/pallets/collator-allowlist/src/lib.rs b/pallets/collator-allowlist/src/lib.rs index 58a3d8a44b..0499916214 100644 --- a/pallets/collator-allowlist/src/lib.rs +++ b/pallets/collator-allowlist/src/lib.rs @@ -37,7 +37,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -49,7 +48,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The Validator Id type - type ValidatorId: Member + Parameter + MaybeSerializeDeserialize; + type ValidatorId: Member + Parameter + MaybeSerializeDeserialize + MaxEncodedLen; /// Type representing the underlying validator registration center. /// It offers us the API we need to check whether a collator diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 00a05a4be6..ab4aca3049 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -15,7 +15,7 @@ use core::convert::TryFrom; use cfg_traits::PoolInspect; use cfg_utils::vec_to_fixed_array; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{ fungibles::{Inspect, Mutate, Transfer}, OriginTrait, @@ -38,7 +38,7 @@ mod contract; pub use contract::*; /// The Parachains that Centrifuge Connectors support. -#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub enum ParachainId { /// Moonbeam - It may be Moonbeam on Polkadot, Moonriver on Kusama, or Moonbase on a testnet. @@ -53,7 +53,7 @@ type EVMChainId = u64; /// The domain indices need to match those used in the EVM contracts and these /// need to pass the Centrifuge domain to send tranche tokens from the other /// domain here. Therefore, DO NOT remove or move variants around. -#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Domain { /// An EVM domain, identified by its EVM Chain Id @@ -117,7 +117,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -457,7 +456,12 @@ pub mod pallet { ) -> Vec { let mut encoded: Vec = Vec::new(); - encoded.append(&mut xcm_domain.ethereum_xcm_transact_call_index.clone()); + encoded.append( + &mut xcm_domain + .ethereum_xcm_transact_call_index + .clone() + .into_inner(), + ); encoded.append( &mut xcm_primitives::EthereumXcmTransaction::V1( xcm_primitives::EthereumXcmTransactionV1 { diff --git a/pallets/connectors/src/routers.rs b/pallets/connectors/src/routers.rs index 5f1d170f6a..13066d4c12 100644 --- a/pallets/connectors/src/routers.rs +++ b/pallets/connectors/src/routers.rs @@ -1,10 +1,10 @@ -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::H160; -use sp_std::vec::Vec; +use sp_runtime::{traits::ConstU32, BoundedVec}; use xcm::VersionedMultiLocation; -#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Router { // An XCM-based router @@ -22,9 +22,34 @@ pub struct XcmDomain { /// It should contain the pallet index + the `transact` call index, to which /// we will append the eth_tx param. You can obtain this value by building /// an ethereum_xcm::transact call with Polkadot JS on the target chain. - pub ethereum_xcm_transact_call_index: Vec, + pub ethereum_xcm_transact_call_index: + BoundedVec>, /// The ConnectorsXcmRouter contract address on a given domain pub contract_address: H160, /// The currency in which execution fees will be paid on pub fee_currency: CurrencyId, } + +// NOTE: Remove this custom implementation once the following underlying data implements MaxEncodedLen: +/// * Polkadot Repo: xcm::VersionedMultiLocation +/// * PureStake Repo: pallet_xcm_transactor::Config::CurrencyId +impl MaxEncodedLen for XcmDomain +where + XcmDomain: Encode, +{ + fn max_encoded_len() -> usize { + // The domain's `VersionedMultiLocation` (custom bound) + xcm::v1::MultiLocation::max_encoded_len() + // From the enum wrapping of `VersionedMultiLocation` + .saturating_add(1) + // The ethereum xcm call index (default bound) + .saturating_add(BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }>, + >::max_encoded_len()) + // The contract address (default bound) + .saturating_add(H160::max_encoded_len()) + // The fee currency (custom bound) + .saturating_add(cfg_types::tokens::CurrencyId::max_encoded_len()) + } +} diff --git a/pallets/crowdloan-claim/src/lib.rs b/pallets/crowdloan-claim/src/lib.rs index 7f6cd02d05..ac09ddcf54 100644 --- a/pallets/crowdloan-claim/src/lib.rs +++ b/pallets/crowdloan-claim/src/lib.rs @@ -202,7 +202,6 @@ pub mod pallet { // for the pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); // ------------------------------------------------------------------------ @@ -233,7 +232,8 @@ pub mod pallet { + Member + Ord + Parameter - + Into; + + Into + + MaxEncodedLen; /// The maximum length (i.e. depth of the tree) we allow a proof to have. /// This mitigates DDoS attacks solely. We choose 30, which by a base 2 merkle-tree diff --git a/pallets/crowdloan-reward/src/lib.rs b/pallets/crowdloan-reward/src/lib.rs index aad0656f4f..7cafd436f9 100644 --- a/pallets/crowdloan-reward/src/lib.rs +++ b/pallets/crowdloan-reward/src/lib.rs @@ -144,7 +144,6 @@ pub mod pallet { // Declare pallet structure placeholder #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); // ---------------------------------------------------------------------------- diff --git a/pallets/fees/src/lib.rs b/pallets/fees/src/lib.rs index 08a14402fe..1e472e06f4 100644 --- a/pallets/fees/src/lib.rs +++ b/pallets/fees/src/lib.rs @@ -46,13 +46,12 @@ pub mod pallet { // method. #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] pub trait Config: frame_system::Config + pallet_authorship::Config { /// Key type used for storing and identifying fees. - type FeeKey: FeeKey + EncodeLike; + type FeeKey: FeeKey + EncodeLike + MaxEncodedLen; /// The currency mechanism. type Currency: Currency; diff --git a/pallets/interest-accrual/src/lib.rs b/pallets/interest-accrual/src/lib.rs index 117c21a5e5..1b081d61b9 100644 --- a/pallets/interest-accrual/src/lib.rs +++ b/pallets/interest-accrual/src/lib.rs @@ -56,7 +56,7 @@ use cfg_primitives::{Moment, SECONDS_PER_YEAR}; use cfg_traits::InterestAccrual; use cfg_types::adjustments::Adjustment; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::UnixTime; use scale_info::TypeInfo; use sp_arithmetic::traits::{checked_pow, One, Zero}; @@ -90,14 +90,14 @@ pub struct RateDetailsV0 { pub last_updated: Moment, } -#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub struct RateDetails { pub accumulated_rate: InterestRate, pub reference_count: u32, } -#[derive(Encode, Decode, TypeInfo, PartialEq)] +#[derive(Encode, Decode, TypeInfo, PartialEq, MaxEncodedLen)] #[repr(u32)] pub enum Release { V0, @@ -120,7 +120,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -146,7 +145,8 @@ pub mod pallet { + Default + Copy + TypeInfo - + FixedPointNumber; + + FixedPointNumber + + MaxEncodedLen; type Time: UnixTime; diff --git a/pallets/investments/src/lib.rs b/pallets/investments/src/lib.rs index d705dd343a..4af3adf980 100644 --- a/pallets/investments/src/lib.rs +++ b/pallets/investments/src/lib.rs @@ -187,7 +187,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The underlying investments one can invest into - type InvestmentId: Member + Parameter + Copy; + type InvestmentId: Member + Parameter + Copy + MaxEncodedLen; /// Something that knows how to handle accounting for the given investments /// and provides metadata about them @@ -218,7 +218,8 @@ pub mod pallet { + Default + Copy + FixedPointNumber - + FixedPointNumberExtension; + + FixedPointNumberExtension + + MaxEncodedLen; /// The bound on how many fulfilled orders we cache until /// the user needs to collect them. @@ -243,7 +244,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] diff --git a/pallets/investments/src/mock.rs b/pallets/investments/src/mock.rs index c4d1449f6e..bcc1117a8f 100644 --- a/pallets/investments/src/mock.rs +++ b/pallets/investments/src/mock.rs @@ -22,7 +22,7 @@ use cfg_types::{ orders::{FulfillmentWithPrice, TotalOrder}, tokens::CurrencyId, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::DispatchResultWithPostInfo, parameter_types, @@ -181,6 +181,7 @@ impl PreConditions for Always { TypeInfo, Serialize, Deserialize, + MaxEncodedLen, )] pub enum InvestmentId { PoolTranche { diff --git a/pallets/keystore/src/lib.rs b/pallets/keystore/src/lib.rs index baa9e01497..c8a5401194 100644 --- a/pallets/keystore/src/lib.rs +++ b/pallets/keystore/src/lib.rs @@ -27,19 +27,19 @@ mod tests; pub mod weights; -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum KeyPurpose { P2PDiscovery, P2PDocumentSigning, } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum KeyType { ECDSA, EDDSA, } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Key { purpose: KeyPurpose, key_type: KeyType, @@ -98,7 +98,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// Keys that are currently stored. diff --git a/pallets/loans/src/lib.rs b/pallets/loans/src/lib.rs index ec16015896..31226e71dc 100644 --- a/pallets/loans/src/lib.rs +++ b/pallets/loans/src/lib.rs @@ -98,7 +98,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -113,7 +112,8 @@ pub mod pallet { + Copy + Default + TypeInfo - + IsType>; + + IsType> + + MaxEncodedLen; /// The LoanId/InstanceId type type LoanId: Parameter @@ -122,10 +122,16 @@ pub mod pallet { + Copy + TypeInfo + From - + IsType>; + + IsType> + + MaxEncodedLen; /// the rate type - type Rate: Parameter + Member + MaybeSerializeDeserialize + FixedPointNumber + TypeInfo; + type Rate: Parameter + + Member + + MaybeSerializeDeserialize + + FixedPointNumber + + TypeInfo + + MaxEncodedLen; type Balance: Member + Parameter @@ -152,7 +158,7 @@ pub mod pallet { /// Pool reserve type type Pool: PoolReserve; - type CurrencyId: Parameter + Copy; + type CurrencyId: Parameter + Copy + MaxEncodedLen; /// Permission type that verifies permissions of users type Permission: PermissionsT< diff --git a/pallets/loans/src/loan_type.rs b/pallets/loans/src/loan_type.rs index d4d0a63d11..819ccbcf5f 100644 --- a/pallets/loans/src/loan_type.rs +++ b/pallets/loans/src/loan_type.rs @@ -12,12 +12,13 @@ // GNU General Public License for more details. //! Module provides functionality for different loan types +use codec::MaxEncodedLen; use scale_info::TypeInfo; use super::*; /// different types of loans -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum LoanType { @@ -49,7 +50,7 @@ where } /// The data structure for Bullet loan type -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct BulletLoan { @@ -127,7 +128,7 @@ where } /// The data structure for Credit line loan type -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct CreditLine { @@ -169,7 +170,7 @@ impl CreditLine { } /// The data structure for Credit line with maturity loan type -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct CreditLineWithMaturity { diff --git a/pallets/loans/src/mock.rs b/pallets/loans/src/mock.rs index 9cca1b11c6..79b5c42b0d 100644 --- a/pallets/loans/src/mock.rs +++ b/pallets/loans/src/mock.rs @@ -262,6 +262,7 @@ impl PoolUpdateGuard for UpdateGuard { TrancheWeight, TrancheId, PoolId, + MaxTranches, >; type ScheduledUpdateDetails = ScheduledUpdateDetails; @@ -339,8 +340,8 @@ impl pallet_interest_accrual::Config for Runtime { } parameter_types! { - #[derive(Debug, Eq, PartialEq, scale_info::TypeInfo, Clone)] - pub const MaxTranches: u8 = 5; + #[derive(Debug, Eq, PartialEq, PartialOrd, scale_info::TypeInfo, Clone)] + pub const MaxTranches: u32 = 5; #[derive(Debug, Eq, PartialEq, scale_info::TypeInfo, Clone)] pub const MinDelay: Moment = 0; @@ -351,10 +352,12 @@ impl pallet_permissions::Config for Runtime { type AdminOrigin = EnsureSignedBy; type Editors = Everything; type MaxRolesPerScope = MaxRoles; + type MaxTranches = MaxTranches; type Role = Role; type RuntimeEvent = RuntimeEvent; type Scope = PermissionScope; - type Storage = PermissionRoles, MinDelay, TrancheId, Moment>; + type Storage = + PermissionRoles, MinDelay, TrancheId, MaxTranches, Moment>; type WeightInfo = (); } diff --git a/pallets/loans/src/test_utils.rs b/pallets/loans/src/test_utils.rs index 700ab63492..71c1200063 100644 --- a/pallets/loans/src/test_utils.rs +++ b/pallets/loans/src/test_utils.rs @@ -30,7 +30,11 @@ use frame_support::{ }; use frame_system::RawOrigin; #[cfg(feature = "runtime-benchmarks")] -use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheMetadata, TrancheType}; +use pallet_pool_system::tranches::TrancheLoc; +use pallet_pool_system::{ + tranches::{TrancheInput, TrancheMetadata, TrancheType}, + Pallet as PoolPallet, Pool as PoolStorage, +}; use sp_runtime::{ traits::{AccountIdConversion, Zero}, Perquintill, diff --git a/pallets/loans/src/types.rs b/pallets/loans/src/types.rs index 89dc1a9dc7..ce02496f0c 100644 --- a/pallets/loans/src/types.rs +++ b/pallets/loans/src/types.rs @@ -13,6 +13,7 @@ //! Module provides base types and their functions use cfg_traits::PoolInspect; +use codec::MaxEncodedLen; use frame_support::RuntimeDebug; use scale_info::TypeInfo; use sp_arithmetic::traits::Zero; @@ -20,7 +21,7 @@ use sp_arithmetic::traits::Zero; use super::*; /// Asset that represents a non fungible -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, Default, Debug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, Default, Debug, TypeInfo, MaxEncodedLen)] pub struct Asset(pub ClassId, pub InstanceId); impl Asset { @@ -37,7 +38,9 @@ pub(crate) struct ClosedLoan { } /// The data structure for storing pool nav details -#[derive(Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo)] +#[derive( + Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct NAVDetails { // this is the latest nav for the given pool. @@ -54,7 +57,9 @@ pub struct NAVDetails { } /// The data structure for storing a specific write off group -#[derive(Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo)] +#[derive( + Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct WriteOffGroup { /// percentage of outstanding debt we are going to write off on a loan @@ -68,7 +73,9 @@ pub struct WriteOffGroup { } /// The data structure as input for creating a write-off group -#[derive(Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo)] +#[derive( + Encode, Decode, Copy, Clone, PartialEq, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct WriteOffGroupInput { /// percentage of outstanding debt we are going to write off on a loan @@ -81,7 +88,7 @@ pub struct WriteOffGroupInput { pub(crate) penalty_interest_rate_per_year: Rate, } -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum WriteOffStatus { @@ -111,7 +118,7 @@ pub enum WriteOffAction { } /// The data structure for storing loan status -#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(any(feature = "std", feature = "runtime-benchmarks"), derive(Debug))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum LoanStatus { @@ -136,14 +143,14 @@ pub enum NAVUpdateType { } /// The data structure for storing loan info -#[derive(Encode, Decode, Copy, Clone, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct LoanDetails { +pub struct LoanDetails { pub(crate) collateral: Asset, pub(crate) status: LoanStatus, } -#[derive(Encode, Decode, Copy, Clone, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] pub struct PricedLoanDetails { pub(crate) loan_id: LoanId, diff --git a/pallets/migration/src/lib.rs b/pallets/migration/src/lib.rs index 920ce4d0fc..9a5bd9154e 100644 --- a/pallets/migration/src/lib.rs +++ b/pallets/migration/src/lib.rs @@ -7,7 +7,9 @@ #![allow(clippy::type_complexity)] use codec::{Decode, Encode}; -use frame_support::{dispatch::DispatchResult, ensure, traits::Currency}; +use frame_support::{ + dispatch::DispatchResult, ensure, pallet_prelude::MaxEncodedLen, traits::Currency, +}; pub use pallet::*; use scale_info::TypeInfo; pub use weights::*; @@ -27,7 +29,7 @@ type BalanceOf = <::Currency as Currency< ::AccountId, >>::Balance; -#[derive(Encode, Decode, PartialEq, Clone, TypeInfo)] +#[derive(Encode, Decode, PartialEq, Clone, TypeInfo, MaxEncodedLen)] pub enum MigrationStatus { Inactive, Ongoing, @@ -57,7 +59,6 @@ pub mod pallet { // method. #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/pallets/nft-sales/src/lib.rs b/pallets/nft-sales/src/lib.rs index adb4f84c7d..86149f314e 100644 --- a/pallets/nft-sales/src/lib.rs +++ b/pallets/nft-sales/src/lib.rs @@ -11,7 +11,7 @@ //! To buy an NFT, users will call `buy`. //! #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{ fungibles::{self, Transfer as FungiblesTransfer}, tokens::nonfungibles::{self, Inspect as _, Transfer as _}, @@ -49,14 +49,14 @@ type CollectionIdOf = type ItemIdOf = <::NonFungibles as nonfungibles::Inspect>>::ItemId; // Storage types -#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub struct Sale { pub seller: AccountId, pub price: Price, } -#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub struct Price { pub currency: CurrencyId, @@ -73,7 +73,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub (super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -96,7 +95,8 @@ pub mod pallet { + Copy + Default + TypeInfo - + IsType>; + + IsType> + + MaxEncodedLen; /// The NFT ItemId type type ItemId: Parameter @@ -105,7 +105,8 @@ pub mod pallet { + Copy + TypeInfo + From - + IsType>; + + IsType> + + MaxEncodedLen; /// The Id of this pallet #[pallet::constant] diff --git a/pallets/nft/src/lib.rs b/pallets/nft/src/lib.rs index 634c836329..100e1479ed 100644 --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -75,7 +75,6 @@ pub mod pallet { // for the pallet. #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); // ------------------------------------------------------------------------ diff --git a/pallets/permissions/src/lib.rs b/pallets/permissions/src/lib.rs index a8a3586c80..65fe9958cc 100644 --- a/pallets/permissions/src/lib.rs +++ b/pallets/permissions/src/lib.rs @@ -49,11 +49,15 @@ pub mod pallet { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type Scope: Member + Parameter; + type Scope: Member + Parameter + MaxEncodedLen; type Role: Member + Parameter; - type Storage: Member + Parameter + Properties + Default; + type Storage: Member + + Parameter + + Properties + + Default + + MaxEncodedLen; type Editors: Contains<(Self::AccountId, Option, Self::Scope, Self::Role)>; @@ -62,12 +66,15 @@ pub mod pallet { #[pallet::constant] type MaxRolesPerScope: Get; + /// The maximum number of tranches. + #[pallet::constant] + type MaxTranches: Get; + type WeightInfo: WeightInfo; } #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::storage] diff --git a/pallets/permissions/src/mock.rs b/pallets/permissions/src/mock.rs index a2a815c410..c7718a0444 100644 --- a/pallets/permissions/src/mock.rs +++ b/pallets/permissions/src/mock.rs @@ -10,7 +10,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; pub use dummy::pallet as pallet_dummy; use frame_support::{ parameter_types, @@ -50,7 +50,7 @@ pub enum Role { bitflags::bitflags! { /// The current admin roles we support - #[derive(codec::Encode, codec::Decode, scale_info::TypeInfo)] + #[derive(codec::Encode, codec::Decode, scale_info::TypeInfo, MaxEncodedLen)] pub struct OrgStorage: u32 { const SENIOR_EXEC = 0b00000001; const HEAD_OF_SAUBERMACHING = 0b00000010; @@ -60,14 +60,16 @@ bitflags::bitflags! { bitflags::bitflags! { /// The current admin roles we support - #[derive(codec::Encode, codec::Decode, scale_info::TypeInfo)] + #[derive(codec::Encode, codec::Decode, scale_info::TypeInfo, MaxEncodedLen)] pub struct XcmStorage: u32 { const SENDER = 0b00000001; const RECEIVER = 0b00000010; } } -#[derive(codec::Encode, codec::Decode, scale_info::TypeInfo, Debug, Clone, Eq, PartialEq)] +#[derive( + codec::Encode, codec::Decode, scale_info::TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen, +)] pub struct Storage { org: OrgStorage, xcm: XcmStorage, @@ -82,7 +84,9 @@ impl Default for Storage { } } -#[derive(codec::Encode, codec::Decode, scale_info::TypeInfo, Debug, Clone, Eq, PartialEq)] +#[derive( + codec::Encode, codec::Decode, scale_info::TypeInfo, Debug, Clone, Eq, PartialEq, MaxEncodedLen, +)] pub enum Scope { PalletA, PalletB, @@ -281,6 +285,7 @@ impl frame_system::Config for Runtime { parameter_types! { pub const One: u64 = 1; pub const MaxRoles: u32 = 10; + pub const MaxTranches: u32 = 5; } type AdminOrigin = EitherOfDiverse, EnsureSignedBy>; @@ -289,6 +294,7 @@ impl pallet_permissions::Config for Runtime { type AdminOrigin = AdminOrigin; type Editors = Editors; type MaxRolesPerScope = MaxRoles; + type MaxTranches = MaxTranches; type Role = Role; type RuntimeEvent = RuntimeEvent; type Scope = Scope; diff --git a/pallets/pool-registry/src/lib.rs b/pallets/pool-registry/src/lib.rs index 7789ce8f56..7c617a775e 100644 --- a/pallets/pool-registry/src/lib.rs +++ b/pallets/pool-registry/src/lib.rs @@ -15,7 +15,7 @@ use cfg_primitives::Moment; use cfg_traits::{Permissions, PoolMutate, UpdateState}; use cfg_types::permissions::{PermissionScope, PoolRole, Role}; -use codec::HasCompact; +use codec::{HasCompact, MaxEncodedLen}; use frame_support::{pallet_prelude::*, scale_info::TypeInfo, transactional, BoundedVec}; use frame_system::pallet_prelude::*; pub use pallet::*; @@ -34,7 +34,7 @@ mod mock; mod tests; pub mod weights; -#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo)] +#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo, MaxEncodedLen)] pub struct TrancheMetadata where MaxTokenNameLength: Get, @@ -44,7 +44,7 @@ where pub token_symbol: BoundedVec, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct PoolMetadata where MetaSize: Get, @@ -52,7 +52,7 @@ where metadata: BoundedVec, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum PoolRegistrationStatus { Registered, Unregistered, @@ -98,7 +98,12 @@ pub mod pallet { + MaxEncodedLen + core::fmt::Debug; - type Rate: Parameter + Member + MaybeSerializeDeserialize + FixedPointNumber + TypeInfo; + type Rate: Parameter + + Member + + MaybeSerializeDeserialize + + FixedPointNumber + + TypeInfo + + MaxEncodedLen; /// A fixed-point number which represents an /// interest rate. @@ -158,7 +163,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::storage] diff --git a/pallets/pool-registry/src/mock.rs b/pallets/pool-registry/src/mock.rs index c3fe046bdd..d943d989ff 100644 --- a/pallets/pool-registry/src/mock.rs +++ b/pallets/pool-registry/src/mock.rs @@ -103,7 +103,7 @@ parameter_types! { /// The index with which this pallet is instantiated in this runtime. pub PoolPalletIndex: u8 = ::index() as u8; - #[derive(scale_info::TypeInfo, Eq, PartialEq, Debug, Clone, Copy )] + #[derive(scale_info::TypeInfo, Eq, PartialEq, PartialOrd, Debug, Clone, Copy )] pub const MaxTranches: u32 = 5; pub const MinUpdateDelay: u64 = 0; // for testing purposes @@ -351,6 +351,7 @@ impl PoolUpdateGuard for UpdateGuard { TrancheWeight, TrancheId, u64, + MaxTranches, >; type ScheduledUpdateDetails = ScheduledUpdateDetails; diff --git a/pallets/pool-system/src/impls.rs b/pallets/pool-system/src/impls.rs index 5b66571901..6bd66783c0 100644 --- a/pallets/pool-system/src/impls.rs +++ b/pallets/pool-system/src/impls.rs @@ -126,6 +126,7 @@ impl PoolMutate for Pallet { T::TrancheCurrency, T::TrancheId, T::PoolId, + T::MaxTranches, >::from_input::( pool_id, tranche_inputs.clone(), diff --git a/pallets/pool-system/src/lib.rs b/pallets/pool-system/src/lib.rs index a70e9fbec3..0bf1a08f00 100644 --- a/pallets/pool-system/src/lib.rs +++ b/pallets/pool-system/src/lib.rs @@ -91,6 +91,7 @@ pub type EpochExecutionTranchesOf = EpochExecutionTranches< ::Rate, ::TrancheWeight, ::TrancheCurrency, + ::MaxTranches, >; /// Types alias for Tranches @@ -101,6 +102,7 @@ pub type TranchesOf = Tranches< ::TrancheCurrency, ::TrancheId, ::PoolId, + ::MaxTranches, >; #[allow(dead_code)] @@ -123,6 +125,7 @@ pub type PoolDetailsOf = PoolDetails< ::TrancheWeight, ::TrancheId, ::PoolId, + ::MaxTranches, >; /// Type alias for `struct EpochExecutionInfo` @@ -133,6 +136,7 @@ type EpochExecutionInfoOf = EpochExecutionInfo< ::TrancheWeight, ::BlockNumber, ::TrancheCurrency, + ::MaxTranches, >; /// Type alias for `struct PoolDepositInfo` @@ -193,7 +197,8 @@ pub mod pallet { + Default + Copy + TypeInfo - + FixedPointNumber; + + FixedPointNumber + + MaxEncodedLen; #[pallet::constant] type PalletId: Get; @@ -229,7 +234,7 @@ pub mod pallet { + TypeInfo + Into; - type CurrencyId: Parameter + Copy; + type CurrencyId: Parameter + Copy + MaxEncodedLen; type PoolCurrency: Contains; @@ -319,7 +324,7 @@ pub mod pallet { /// Max number of Tranches #[pallet::constant] - type MaxTranches: Get + Member + scale_info::TypeInfo; + type MaxTranches: Get + Member + PartialOrd + scale_info::TypeInfo; /// The amount that must be reserved to create a pool #[pallet::constant] @@ -334,7 +339,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::storage] @@ -376,7 +380,7 @@ pub mod pallet { SolutionSubmitted { pool_id: T::PoolId, epoch_id: T::EpochId, - solution: EpochSolution, + solution: EpochSolution, }, /// An epoch was executed. EpochExecuted { @@ -892,7 +896,7 @@ pub mod pallet { pool_id: &PoolDetailsOf, epoch: &EpochExecutionInfoOf, solution: &[TrancheSolution], - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { match Self::inspect_solution(pool_id, epoch, solution)? { PoolState::Healthy => { EpochSolution::score_solution_healthy(solution, &epoch.tranches) @@ -918,21 +922,24 @@ pub mod pallet { Error::::InvalidSolution ); - let (acc_invest, acc_redeem, risk_buffers) = - calculate_solution_parameters::<_, _, T::Rate, _, T::TrancheCurrency>( - &epoch.tranches, - solution, - ) - .map_err(|e| { - // In case we have an underflow in the calculation, there - // is not enough balance in the tranches to realize the redeemptions. - // We convert this at the pool level into an InsufficientCurrency error. - if e == DispatchError::Arithmetic(ArithmeticError::Underflow) { - Error::::InsufficientCurrency - } else { - Error::::InvalidSolution - } - })?; + let (acc_invest, acc_redeem, risk_buffers) = calculate_solution_parameters::< + _, + _, + T::Rate, + _, + T::TrancheCurrency, + T::MaxTranches, + >(&epoch.tranches, solution) + .map_err(|e| { + // In case we have an underflow in the calculation, there + // is not enough balance in the tranches to realize the redeemptions. + // We convert this at the pool level into an InsufficientCurrency error. + if e == DispatchError::Arithmetic(ArithmeticError::Underflow) { + Error::::InsufficientCurrency + } else { + Error::::InvalidSolution + } + })?; let currency_available: T::Balance = acc_invest .checked_add(&epoch.reserve) diff --git a/pallets/pool-system/src/mock.rs b/pallets/pool-system/src/mock.rs index 1f2ba5adea..b0a75f6f32 100644 --- a/pallets/pool-system/src/mock.rs +++ b/pallets/pool-system/src/mock.rs @@ -80,10 +80,12 @@ impl pallet_permissions::Config for Runtime { type AdminOrigin = EnsureSignedBy; type Editors = frame_support::traits::Everything; type MaxRolesPerScope = MaxRoles; + type MaxTranches = MaxTranches; type Role = Role; type RuntimeEvent = RuntimeEvent; type Scope = PermissionScope; - type Storage = PermissionRoles, MinDelay, TrancheId, Moment>; + type Storage = + PermissionRoles, MinDelay, TrancheId, MaxTranches, Moment>; type WeightInfo = (); } @@ -277,7 +279,7 @@ parameter_types! { /// The index with which this pallet is instantiated in this runtime. pub PoolPalletIndex: u8 = ::index() as u8; - #[derive(scale_info::TypeInfo, Eq, PartialEq, Debug, Clone, Copy )] + #[derive(scale_info::TypeInfo, Eq, PartialEq, PartialOrd, Debug, Clone, Copy )] pub const MaxTranches: u32 = 5; pub const MinUpdateDelay: u64 = 0; // no delay @@ -366,6 +368,7 @@ impl PoolUpdateGuard for UpdateGuard { TrancheWeight, TrancheId, u64, + MaxTranches, >; type ScheduledUpdateDetails = ScheduledUpdateDetails; diff --git a/pallets/pool-system/src/pool_types.rs b/pallets/pool-system/src/pool_types.rs index 3da835e9b1..82c6c7f160 100644 --- a/pallets/pool-system/src/pool_types.rs +++ b/pallets/pool-system/src/pool_types.rs @@ -13,7 +13,7 @@ use cfg_primitives::Moment; use cfg_traits::ops::{EnsureAdd, EnsureAddAssign, EnsureSub}; use cfg_types::epoch::EpochState; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, traits::Get, @@ -38,7 +38,7 @@ impl TypeId for PoolLocator { const TYPE_ID: [u8; 4] = *b"pool"; } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ReserveDetails { /// Investments will be allowed up to this amount. pub max: Balance, @@ -52,14 +52,21 @@ impl ReserveDetails where Balance: AtLeast32BitUnsigned + Copy + From, { - pub fn deposit_from_epoch( + pub fn deposit_from_epoch( &mut self, - epoch_tranches: &EpochExecutionTranches, + epoch_tranches: &EpochExecutionTranches< + Balance, + BalanceRatio, + Weight, + TrancheCurrency, + MaxExecutionTranches, + >, solution: &[TrancheSolution], ) -> DispatchResult where Weight: Copy + From, BalanceRatio: Copy, + MaxExecutionTranches: Get, { let executed_amounts = epoch_tranches.fulfillment_cash_flows(solution)?; @@ -79,7 +86,7 @@ where } } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ScheduledUpdateDetails where MaxTokenNameLength: Get, @@ -96,7 +103,7 @@ pub struct PoolLocator { pub pool_id: PoolId, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct PoolDetails< CurrencyId, TrancheCurrency, @@ -107,15 +114,17 @@ pub struct PoolDetails< Weight, TrancheId, PoolId, + MaxTranches, > where MetaSize: Get + Copy, Rate: FixedPointNumber, Balance: FixedPointOperand, + MaxTranches: Get, { /// Currency that the pool is denominated in (immutable). pub currency: CurrencyId, /// List of tranches, ordered junior to senior. - pub tranches: Tranches, + pub tranches: Tranches, /// Details about the parameters of the pool. pub parameters: PoolParameters, /// Metadata that specifies the pool. @@ -128,12 +137,12 @@ pub struct PoolDetails< pub reserve: ReserveDetails, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum PoolStatus { Open, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct PoolParameters { /// Minimum duration for an epoch. pub min_epoch_time: Moment, @@ -155,8 +164,37 @@ where pub max_nav_age: Change, } +// NOTE: Can be removed once orml_traits::Change impls MaxEncodedLen +// https://github.com/open-web3-stack/open-runtime-module-library/pull/867 +impl MaxEncodedLen + for PoolChanges +where + MaxTokenNameLength: Get, + MaxTokenSymbolLength: Get, + MaxTranches: Get, + PoolChanges: Encode, + BoundedVec, MaxTranches>: MaxEncodedLen, + BoundedVec, MaxTranches>: + MaxEncodedLen, + Moment: MaxEncodedLen, +{ + fn max_encoded_len() -> usize { + // The tranches (default bound) + BoundedVec::, MaxTranches>::max_encoded_len() + // The tranche metadata (default bound) + .saturating_add(BoundedVec::< + TrancheMetadata, + MaxTranches, + >::max_encoded_len()) + // The min epoc time and max nav age (default bounds) + .saturating_add(Moment::max_encoded_len().saturating_mul(2)) + // From the `Change` enum which wraps all four fields of Self + .saturating_add(4) + } +} + /// Information about the deposit that has been taken to create a pool -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct PoolDepositInfo { pub depositor: AccountId, pub deposit: Balance, @@ -189,7 +227,18 @@ pub struct PoolEssence< Vec>, } -impl +impl< + CurrencyId, + TrancheCurrency, + EpochId, + Balance, + Rate, + MetaSize, + Weight, + TrancheId, + PoolId, + MaxTranches, + > PoolDetails< CurrencyId, TrancheCurrency, @@ -200,6 +249,7 @@ impl where Balance: FixedPointOperand + BaseArithmetic + Unsigned + From, CurrencyId: Copy, @@ -210,6 +260,7 @@ impl, TrancheId: Clone + From<[u8; 16]> + PartialEq, Weight: Copy + From, + MaxTranches: Get, { pub fn start_next_epoch(&mut self, now: Moment) -> DispatchResult { self.epoch.current.ensure_add_assign(One::one())?; diff --git a/pallets/pool-system/src/solution.rs b/pallets/pool-system/src/solution.rs index 82e0c641ff..59eff6bb06 100644 --- a/pallets/pool-system/src/solution.rs +++ b/pallets/pool-system/src/solution.rs @@ -11,10 +11,11 @@ // GNU General Public License for more details. use cfg_traits::ops::{EnsureAdd, EnsureAddAssign, EnsureFixedPointNumber, EnsureMul, EnsureSub}; +use codec::MaxEncodedLen; use frame_support::sp_runtime::traits::Convert; use sp_arithmetic::traits::Unsigned; use sp_runtime::ArithmeticError; -use sp_std::vec; +use sp_std::{ops::Deref, vec}; use super::*; use crate::tranches::{calculate_risk_buffers, EpochExecutionTranches, TrancheSolution}; @@ -86,7 +87,7 @@ impl PoolState { } } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum UnhealthyState { MaxReserveViolated, @@ -94,27 +95,43 @@ pub enum UnhealthyState { } /// The solutions struct for epoch solution -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum EpochSolution { - Healthy(HealthySolution), - Unhealthy(UnhealthySolution), +pub enum EpochSolution +where + MaxTranches: Get, +{ + Healthy(HealthySolution), + Unhealthy(UnhealthySolution), } /// The information for a currently executing epoch -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct EpochExecutionInfo +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct EpochExecutionInfo< + Balance, + BalanceRatio, + EpochId, + Weight, + BlockNumber, + TrancheCurrency, + MaxTranches, +> where + MaxTranches: Get, { pub epoch: EpochId, pub nav: Balance, pub reserve: Balance, pub max_reserve: Balance, - pub tranches: EpochExecutionTranches, - pub best_submission: Option>, + pub tranches: + EpochExecutionTranches, + pub best_submission: Option>, pub challenge_period_end: Option, } -impl EpochSolution { +impl EpochSolution +where + MaxTranches: Get, +{ /// Calculates the score for a given solution. Should only be called inside the /// `fn score_solution()` from the runtime, as there are no checks if solution /// length matches tranche length. @@ -131,14 +148,21 @@ impl EpochSolution { /// score = ||X||1 /// /// Returns error upon overflow of `Balances`. - pub fn calculate_score( + pub fn calculate_score( solution: &[TrancheSolution], - tranches: &EpochExecutionTranches, + tranches: &EpochExecutionTranches< + Balance, + BalanceRatio, + Weight, + TrancheCurrency, + MaxExecutionTranches, + >, ) -> Result where Balance: Copy + BaseArithmetic + Unsigned + From, Weight: Copy + From + Convert, BalanceRatio: Copy, + MaxExecutionTranches: Get, { let (invest_score, redeem_score) = solution .iter() @@ -168,36 +192,50 @@ impl EpochSolution { } /// Scores a solution and returns a healthy solution as a result. - pub fn score_solution_healthy( + pub fn score_solution_healthy( solution: &[TrancheSolution], - tranches: &EpochExecutionTranches, - ) -> Result, DispatchError> + tranches: &EpochExecutionTranches< + Balance, + BalanceRatio, + Weight, + TrancheCurrency, + MaxExecutionTranches, + >, + ) -> Result, DispatchError> where Balance: Zero + Copy + BaseArithmetic + Unsigned + From, Weight: Copy + From + Convert, BalanceRatio: Copy, + MaxExecutionTranches: Get, { let score = Self::calculate_score(solution, tranches)?; Ok(EpochSolution::Healthy(HealthySolution { - solution: solution.to_vec(), + solution: BoundedVec::truncate_from(solution.to_vec()), score, })) } /// Scores an solution, that would bring a pool into an unhealthy state. /// - pub fn score_solution_unhealthy( + pub fn score_solution_unhealthy( solution: &[TrancheSolution], - tranches: &EpochExecutionTranches, + tranches: &EpochExecutionTranches< + Balance, + BalanceRatio, + Weight, + TrancheCurrency, + MaxExecutionTranches, + >, reserve: Balance, max_reserve: Balance, state: &[UnhealthyState], - ) -> Result, DispatchError> + ) -> Result, DispatchError> where Weight: Copy + From, BalanceRatio: Copy + FixedPointNumber, Balance: Copy + BaseArithmetic + FixedPointOperand + Unsigned + From, + MaxExecutionTranches: Get, { let risk_buffer_improvement_scores = if state.contains(&UnhealthyState::MinRiskBufferViolated) { @@ -256,17 +294,19 @@ impl EpochSolution { }; Ok(EpochSolution::Unhealthy(UnhealthySolution { - state: state.to_vec(), - solution: solution.to_vec(), - risk_buffer_improvement_scores, + state: BoundedVec::truncate_from(state.to_vec()), + solution: BoundedVec::truncate_from(solution.to_vec()), + risk_buffer_improvement_scores: risk_buffer_improvement_scores + .map(|v| BoundedVec::truncate_from(v)), reserve_improvement_score, })) } } -impl EpochSolution +impl EpochSolution where Balance: Copy, + MaxTranches: Get, { pub fn healthy(&self) -> bool { match self { @@ -283,9 +323,10 @@ where } } -impl PartialOrd for EpochSolution +impl PartialOrd for EpochSolution where Balance: PartialOrd, + MaxTranches: Get + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { match (self, other) { @@ -297,42 +338,49 @@ where } } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct HealthySolution { - pub solution: Vec, +pub struct HealthySolution> { + // TODO: Check depedency of Tranches, Solutions and States. E.g. can we use the same max bounds for multiple different bounded vecs? + pub solution: BoundedVec, pub score: Balance, } -impl PartialOrd for HealthySolution +impl PartialOrd for HealthySolution where Balance: PartialOrd, + MaxTranches: Get + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.score.partial_cmp(&other.score) } } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct UnhealthySolution { - pub state: Vec, - pub solution: Vec, +pub struct UnhealthySolution> { + // TODO: Check depedency of Tranches, Solutions and States. E.g. can we use the same max bounds for multiple different bounded vecs? + pub state: BoundedVec, + pub solution: BoundedVec, // The risk buffer score per tranche (less junior tranche) for this solution - pub risk_buffer_improvement_scores: Option>, + pub risk_buffer_improvement_scores: Option>, // The reserve buffer score for this solution pub reserve_improvement_score: Option, } -impl UnhealthySolution { +impl UnhealthySolution +where + MaxTranches: Get, +{ fn has_state(&self, state: &UnhealthyState) -> bool { - self.state.contains(state) + self.state.deref().contains(state) } } -impl PartialOrd for UnhealthySolution +impl PartialOrd for UnhealthySolution where Balance: PartialOrd, + MaxTranches: Get + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { // We check if any of the risk buffer scores are higher. @@ -382,14 +430,15 @@ where } } -pub fn calculate_solution_parameters( - epoch_tranches: &EpochExecutionTranches, +pub fn calculate_solution_parameters( + epoch_tranches: &EpochExecutionTranches, solution: &[TrancheSolution], ) -> Result<(Balance, Balance, Vec), DispatchError> where BalanceRatio: Copy + FixedPointNumber, Balance: Copy + BaseArithmetic + FixedPointOperand + Unsigned + From, Weight: Copy + From, + MaxTranches: Get, { let acc_invest: Balance = epoch_tranches .residual_top_slice() @@ -417,6 +466,7 @@ where #[cfg(test)] mod test { use super::*; + use crate::mock::MaxTranches; fn get_tranche_solution(invest_fulfillment: f64, redeem_fulfillment: f64) -> TrancheSolution { TrancheSolution { @@ -425,17 +475,17 @@ mod test { } } - fn get_solution(fulfillments: Vec<(f64, f64)>) -> Vec { + fn get_solution(fulfillments: Vec<(f64, f64)>) -> BoundedVec { let mut solutions = Vec::new(); fulfillments .into_iter() .for_each(|(invest, redeem)| solutions.push(get_tranche_solution(invest, redeem))); - solutions + BoundedVec::<_, MaxTranches>::truncate_from(solutions) } - fn get_full_solution() -> Vec { + fn get_full_solution() -> BoundedVec { let mut solutions = Vec::new(); solutions.push(get_tranche_solution(1.0, 1.0)); @@ -443,7 +493,7 @@ mod test { solutions.push(get_tranche_solution(1.0, 1.0)); solutions.push(get_tranche_solution(1.0, 1.0)); - solutions + BoundedVec::<_, MaxTranches>::truncate_from(solutions) } #[test] @@ -532,14 +582,16 @@ mod test { #[test] fn epoch_solution_healthy_works() { - let solution = EpochSolution::::Healthy(HealthySolution { + let solution = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 0, }); assert!(solution.healthy()); - let solution = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, @@ -549,104 +601,120 @@ mod test { #[test] fn epoch_solution_solution_works() { - let solution = EpochSolution::::Healthy(HealthySolution { + let solution = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 0, }); - assert!(solution.solution() == get_full_solution()); + assert!(solution.solution() == get_full_solution().as_slice()); - let solution = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, }); - assert!(solution.solution() == get_full_solution()); + assert!(solution.solution() == get_full_solution().as_slice()); } #[test] fn epoch_solution_partial_eq_works() { - let solution_1 = EpochSolution::::Healthy(HealthySolution { + let solution_1 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 3, }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 3, }); assert!(solution_1 == solution_2); - let solution_1 = EpochSolution::::Healthy(HealthySolution { + let solution_1 = EpochSolution::::Healthy(HealthySolution { solution: get_solution(vec![(0.0, 0.0), (1.0, 0.7), (0.7, 0.7)]), score: 3, }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 3, }); assert!(solution_1 != solution_2); - let solution_1 = EpochSolution::::Healthy(HealthySolution { + let solution_1 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 3, }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 4, }); assert!(solution_1 != solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 4, }); assert!(solution_1 != solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, }); assert!(solution_1 == solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(2), risk_buffer_improvement_scores: None, }); assert!(solution_1 != solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_solution(vec![(0.0, 0.0), (1.0, 0.7), (0.7, 0.7)]), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, @@ -657,7 +725,9 @@ mod test { #[test] fn unhealthy_solution_has_state_works() { let unhealthy = UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: get_full_solution(), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, @@ -671,12 +741,12 @@ mod test { // via the `ParitalOrd` implementation of `EpochSolution`, `HealthySolution` and `UnhealthySolution`. #[test] fn higher_score_is_better() { - let solution_1 = EpochSolution::::Healthy(HealthySolution { + let solution_1 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 3, }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: get_full_solution(), score: 4, }); @@ -685,17 +755,19 @@ mod test { #[test] fn healthy_always_above_unhealthy() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![ + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ UnhealthyState::MinRiskBufferViolated, UnhealthyState::MaxReserveViolated, - ], + ]), solution: Default::default(), reserve_improvement_score: Some(1000), - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Healthy(HealthySolution { + let solution_2 = EpochSolution::::Healthy(HealthySolution { solution: Default::default(), score: 0, }); @@ -704,15 +776,19 @@ mod test { #[test] fn reserve_improvement_better() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: Default::default(), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: Default::default(), reserve_improvement_score: Some(6), risk_buffer_improvement_scores: None, @@ -723,14 +799,16 @@ mod test { #[test] fn no_reserve_violation_better() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: Default::default(), reserve_improvement_score: Some(5), risk_buffer_improvement_scores: None, }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { state: Default::default(), solution: Default::default(), reserve_improvement_score: None, @@ -742,18 +820,22 @@ mod test { #[test] fn no_risk_buff_violation_better() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![ + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ UnhealthyState::MaxReserveViolated, UnhealthyState::MinRiskBufferViolated, - ], + ]), solution: Default::default(), reserve_improvement_score: Some(5), - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MaxReserveViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ + UnhealthyState::MaxReserveViolated, + ]), solution: Default::default(), reserve_improvement_score: Some(1000), risk_buffer_improvement_scores: None, @@ -764,24 +846,28 @@ mod test { #[test] fn reserve_improvement_decides_over_equal_min_risk_buff() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![ + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ UnhealthyState::MaxReserveViolated, UnhealthyState::MinRiskBufferViolated, - ], + ]), solution: Default::default(), reserve_improvement_score: Some(5), - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![ + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::<_, MaxTranches>::truncate_from(vec![ UnhealthyState::MaxReserveViolated, UnhealthyState::MinRiskBufferViolated, - ], + ]), solution: Default::default(), reserve_improvement_score: Some(6), - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); assert!(solution_1 < solution_2); @@ -789,50 +875,62 @@ mod test { #[test] fn risk_buff_improvement_better() { - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![2u128, 0u128, 0u128, 0u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::truncate_from(vec![ + 2u128, 0u128, 0u128, 0u128, + ])), // 4 tranches }); assert!(solution_1 < solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 5u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::truncate_from(vec![ + 1u128, 2u128, 3u128, 5u128, + ])), // 4 tranches }); assert!(solution_1 < solution_2); - let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_1 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![1u128, 2u128, 3u128, 4u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 2u128, 3u128, 4u128], + )), // 4 tranches }); - let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { - state: vec![UnhealthyState::MinRiskBufferViolated], + let solution_2 = EpochSolution::::Unhealthy(UnhealthySolution { + state: BoundedVec::truncate_from(vec![UnhealthyState::MinRiskBufferViolated]), solution: Default::default(), reserve_improvement_score: None, - risk_buffer_improvement_scores: Some(vec![1u128, 3u128, 3u128, 5u128]), // 4 tranches + risk_buffer_improvement_scores: Some(BoundedVec::<_, MaxTranches>::truncate_from( + vec![1u128, 3u128, 3u128, 5u128], + )), // 4 tranches }); assert!(solution_1 < solution_2); diff --git a/pallets/pool-system/src/tranches.rs b/pallets/pool-system/src/tranches.rs index b683288679..c593536255 100644 --- a/pallets/pool-system/src/tranches.rs +++ b/pallets/pool-system/src/tranches.rs @@ -20,7 +20,7 @@ use cfg_traits::{ #[cfg(test)] use cfg_types::{fixed_point::Rate, tokens::TrancheCurrency}; use cfg_types::{tokens::CustomMetadata, xcm::XcmMetadata}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::DispatchResult, ensure, @@ -39,7 +39,7 @@ use sp_runtime::{ traits::{ConstU32, Member, One, Zero}, DispatchError, FixedPointNumber, FixedPointOperand, Perquintill, WeakBoundedVec, }; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::{marker::PhantomData, ops::Deref, vec::Vec}; use xcm::{ latest::MultiLocation, prelude::{GeneralKey, PalletInstance, Parachain, X3}, @@ -49,7 +49,7 @@ use xcm::{ /// Type that indicates the seniority of a tranche pub type Seniority = u32; -#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo)] +#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo, MaxEncodedLen)] pub struct TrancheInput where MaxTokenNameLength: Get, @@ -60,7 +60,7 @@ where pub metadata: TrancheMetadata, } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct TrancheUpdate { pub tranche_type: TrancheType, pub seniority: Option, @@ -88,7 +88,7 @@ where pub metadata: TrancheMetadata, } -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum TrancheType { Residual, NonResidual { @@ -129,7 +129,8 @@ where } } -#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo)] +#[derive(Debug, Encode, PartialEq, Eq, Decode, Clone, TypeInfo, MaxEncodedLen)] +// TODO: Why same struct twice? pool-registry and pool-system. Maybe because of circular dependencies? pub struct TrancheMetadata where MaxTokenNameLength: Get, @@ -139,7 +140,7 @@ where pub token_symbol: BoundedVec, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Tranche { pub tranche_type: TrancheType, pub seniority: Seniority, @@ -303,15 +304,20 @@ pub type TrancheIndex = u64; /// are not reusable! pub type TrancheSalt = (TrancheIndex, PoolId); -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct Tranches { - pub tranches: Vec>, - pub ids: Vec, +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct Tranches +where + MaxTranches: Get, +{ + pub tranches: BoundedVec, MaxTranches>, + pub ids: BoundedVec, pub salt: TrancheSalt, } #[cfg(test)] -impl Tranches { +impl + Tranches +{ pub fn new( pool: PoolId, tranches: Vec>, @@ -327,28 +333,34 @@ impl Tranches TrancheCurrency, TrancheId, PoolId, + crate::mock::MaxTranches, >::id_from_salt(salt)); salt = (index.ensure_add(1)?.ensure_into()?, pool); } Ok(Self { - tranches, - ids, + tranches: BoundedVec::< + Tranche, + crate::mock::MaxTranches, + >::truncate_from(tranches), + ids: BoundedVec::::truncate_from(ids), salt, }) } } // The solution struct for a specific tranche -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, TypeInfo)] +#[derive( + Encode, Decode, Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct TrancheSolution { pub invest_fulfillment: Perquintill, pub redeem_fulfillment: Perquintill, } -impl - Tranches +impl + Tranches where TrancheCurrency: Copy + TrancheCurrencyT, Balance: Zero + Copy + BaseArithmetic + FixedPointOperand + Unsigned + From, @@ -356,6 +368,7 @@ where Rate: One + Copy + FixedPointNumber, TrancheId: Clone + From<[u8; 16]> + sp_std::cmp::PartialEq, PoolId: Copy + Encode, + MaxTranches: Get, { pub fn from_input( pool: PoolId, @@ -366,8 +379,8 @@ where MaxTokenNameLength: Get, MaxTokenSymbolLength: Get, { - let tranches = Vec::with_capacity(tranche_inputs.len()); - let ids = Vec::with_capacity(tranche_inputs.len()); + let tranches = BoundedVec::with_bounded_capacity(tranche_inputs.len()); + let ids = BoundedVec::with_bounded_capacity(tranche_inputs.len()); let salt = (0, pool); let mut tranches = Tranches { tranches, @@ -396,7 +409,7 @@ where TrancheLoc::Index(index) => index .try_into() .ok() - .and_then(|index: usize| self.ids.get(index).cloned()), + .and_then(|index: usize| self.ids.deref().get(index).cloned()), } } @@ -448,7 +461,7 @@ where TrancheLoc::Index(index) => { let index: Option = index.try_into().ok(); if let Some(index) = index { - self.tranches.get(index) + self.tranches.deref().get(index) } else { None } @@ -458,7 +471,7 @@ where if let Some(index) = index { let index: Option = index.try_into().ok(); if let Some(index) = index { - self.tranches.get(index) + self.tranches.deref().get(index) } else { None } @@ -483,7 +496,7 @@ where /// -> tranche id = Twox128::hash(salt) fn next_id(&mut self) -> Result { let id = - Tranches::::id_from_salt( + Tranches::::id_from_salt( self.salt, ); self.salt = (self.salt.0.ensure_add(1)?, self.salt.1); @@ -540,7 +553,7 @@ where let at_idx = at; let at: usize = at.ensure_into()?; ensure!( - at <= self.tranches.len(), + at <= self.tranches.deref().len(), DispatchError::Other( "Must add tranches either in between others or at the end. This should be catched somewhere else." ) @@ -573,8 +586,14 @@ where ) ); } - self.tranches.insert(at, new_tranche); - self.ids.insert(at, id); + self.tranches + .try_insert(at, new_tranche) + .map_err(|_| ()) + .expect("at is < len and either 0 or a previous element must exist. qed."); + self.ids + .try_insert(at, id) + .map_err(|_| ()) + .expect("at is < len and either 0 or a previous element must exist. qed."); Ok(()) } @@ -582,7 +601,7 @@ where pub fn remove(&mut self, at: TrancheIndex) -> DispatchResult { let at: usize = at.ensure_into()?; ensure!( - at < self.tranches.len(), + at < self.tranches.deref().len(), DispatchError::Other( "Invalid tranche index. Exceeding number of tranches. This should be catched somewhere else." ) @@ -595,7 +614,7 @@ where } pub fn ids_non_residual_top(&self) -> Vec { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); self.ids.iter().rev().for_each(|id| res.push(id.clone())); res } @@ -608,8 +627,8 @@ where where F: FnMut(&Tranche) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); - for tranche in self.tranches.iter().rev() { + let mut res = Vec::with_capacity(self.tranches.deref().len()); + for tranche in self.tranches.deref().iter().rev() { let r = f(tranche)?; res.push(r) } @@ -620,7 +639,7 @@ where where F: FnMut(&mut Tranche) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); for tranche in self.tranches.iter_mut().rev() { let r = f(tranche)?; res.push(r) @@ -637,7 +656,7 @@ where F: FnMut(&Tranche, W) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); let iter = self.tranches.iter().rev().zip(with.into_iter()); for (tranche, w) in iter { @@ -660,7 +679,7 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); let iter = self.tranches.iter_mut().rev().zip(with.into_iter()); for (tranche, w) in iter { @@ -672,15 +691,15 @@ where } pub fn ids_residual_top(&self) -> Vec { - self.ids.clone() + self.ids.clone().into_inner() } pub fn combine_residual_top(&self, mut f: F) -> Result, DispatchError> where F: FnMut(&Tranche) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); - for tranche in self.tranches.iter() { + let mut res = Vec::with_capacity(self.tranches.deref().len()); + for tranche in self.tranches.deref().iter() { let r = f(tranche)?; res.push(r) } @@ -691,7 +710,7 @@ where where F: FnMut(&mut Tranche) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); for tranche in self.tranches.iter_mut() { let r = f(tranche)?; res.push(r) @@ -708,8 +727,8 @@ where F: FnMut(&Tranche, W) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); - let iter = self.tranches.iter().zip(with.into_iter()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); + let iter = self.tranches.deref().iter().zip(with.into_iter()); for (tranche, w) in iter { let r = f(tranche, w)?; @@ -731,7 +750,7 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); // TODO: Would be nice to error out when with is larger than tranches... let iter = self.tranches.iter_mut().zip(with.into_iter()); @@ -799,17 +818,19 @@ where } pub fn num_tranches(&self) -> usize { - self.tranches.len() + self.tranches.deref().len() } - pub fn into_tranches(self) -> Vec> { + pub fn into_tranches( + self, + ) -> BoundedVec, MaxTranches> { self.tranches } pub fn non_residual_tranches( &self, ) -> Option<&[Tranche]> { - if let Some((_head, tail)) = self.tranches.as_slice().split_first() { + if let Some((_head, tail)) = self.tranches.deref().as_slice().split_first() { Some(tail) } else { None @@ -819,7 +840,7 @@ where pub fn non_residual_tranches_mut( &mut self, ) -> Option<&mut [Tranche]> { - if let Some((_head, tail)) = self.tranches.as_mut_slice().split_first_mut() { + if let Some((_head, tail)) = self.tranches.as_mut().split_first_mut() { Some(tail) } else { None @@ -827,7 +848,7 @@ where } pub fn residual_tranche(&self) -> Option<&Tranche> { - if let Some((head, _tail)) = self.tranches.as_slice().split_first() { + if let Some((head, _tail)) = self.tranches.deref().as_slice().split_first() { Some(head) } else { None @@ -837,7 +858,7 @@ where pub fn residual_tranche_mut( &mut self, ) -> Option<&mut Tranche> { - if let Some((head, _tail)) = self.tranches.as_mut_slice().split_first_mut() { + if let Some((head, _tail)) = self.tranches.as_mut().split_first_mut() { Some(head) } else { None @@ -847,23 +868,23 @@ where pub fn non_residual_top_slice( &self, ) -> &RevSlice> { - self.tranches.rev() + self.tranches.deref().rev() } pub fn non_residual_top_slice_mut( &mut self, ) -> &mut RevSlice> { - self.tranches.rev_mut() + self.tranches.as_mut().rev_mut() } pub fn residual_top_slice(&self) -> &[Tranche] { - self.tranches.as_slice() + self.tranches.deref().as_slice() } pub fn residual_top_slice_mut( &mut self, ) -> &mut [Tranche] { - self.tranches.as_mut_slice() + self.tranches.as_mut() } pub fn supplies(&self) -> Result, DispatchError> { @@ -970,7 +991,7 @@ where } } -#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct EpochExecutionTranche { pub currency: TrancheCurrency, pub supply: Balance, @@ -999,29 +1020,38 @@ impl Default for EpochExecutionTranche { - pub tranches: Vec>, +#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct EpochExecutionTranches +where + MaxTranches: Get, +{ + pub tranches: BoundedVec< + EpochExecutionTranche, + MaxTranches, + >, } /// Utility implementations for `EpochExecutionTranches` -impl - EpochExecutionTranches +impl + EpochExecutionTranches where Balance: Zero + Copy + BaseArithmetic + Unsigned + From, Weight: Copy + From, BalanceRatio: Copy, + MaxTranches: Get, { pub fn new( tranches: Vec>, ) -> Self { - Self { tranches } + Self { + tranches: BoundedVec::truncate_from(tranches), + } } pub fn non_residual_tranches( &self, ) -> Option<&[EpochExecutionTranche]> { - if let Some((_head, tail)) = self.tranches.as_slice().split_first() { + if let Some((_head, tail)) = self.tranches.deref().as_slice().split_first() { Some(tail) } else { None @@ -1031,7 +1061,7 @@ where pub fn non_residual_tranches_mut( &mut self, ) -> Option<&mut [EpochExecutionTranche]> { - if let Some((_head, tail)) = self.tranches.as_mut_slice().split_first_mut() { + if let Some((_head, tail)) = self.tranches.as_mut().split_first_mut() { Some(tail) } else { None @@ -1041,7 +1071,7 @@ where pub fn residual_tranche( &self, ) -> Option<&EpochExecutionTranche> { - if let Some((head, _tail)) = self.tranches.as_slice().split_first() { + if let Some((head, _tail)) = self.tranches.deref().as_slice().split_first() { Some(head) } else { None @@ -1051,7 +1081,7 @@ where pub fn residual_tranche_mut( &mut self, ) -> Option<&mut EpochExecutionTranche> { - if let Some((head, _tail)) = self.tranches.as_mut_slice().split_first_mut() { + if let Some((head, _tail)) = self.tranches.as_mut().split_first_mut() { Some(head) } else { None @@ -1059,37 +1089,40 @@ where } pub fn num_tranches(&self) -> usize { - self.tranches.len() + self.tranches.deref().len() } pub fn into_tranches( self, - ) -> Vec> { + ) -> BoundedVec< + EpochExecutionTranche, + MaxTranches, + > { self.tranches } pub fn non_residual_top_slice( &self, ) -> &RevSlice> { - self.tranches.rev() + self.tranches.deref().rev() } pub fn non_residual_top_slice_mut( &mut self, ) -> &mut RevSlice> { - self.tranches.rev_mut() + self.tranches.as_mut().rev_mut() } pub fn residual_top_slice( &self, ) -> &[EpochExecutionTranche] { - self.tranches.as_slice() + self.tranches.deref().as_slice() } pub fn residual_top_slice_mut( &mut self, ) -> &mut [EpochExecutionTranche] { - self.tranches.as_mut_slice() + self.tranches.as_mut() } pub fn combine_non_residual_top(&self, mut f: F) -> Result, DispatchError> @@ -1098,8 +1131,8 @@ where &EpochExecutionTranche, ) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); - for tranche in self.tranches.iter().rev() { + let mut res = Vec::with_capacity(self.tranches.deref().len()); + for tranche in self.tranches.deref().iter().rev() { let r = f(tranche)?; res.push(r) } @@ -1112,7 +1145,7 @@ where &mut EpochExecutionTranche, ) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); for tranche in &mut self.tranches.iter_mut().rev() { let r = f(tranche)?; res.push(r) @@ -1132,7 +1165,7 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); let iter = self.tranches.iter().rev().zip(with.into_iter()); for (tranche, w) in iter { @@ -1155,7 +1188,7 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); let iter = self.tranches.iter_mut().rev().zip(with.into_iter()); for (tranche, w) in iter { @@ -1172,8 +1205,8 @@ where &EpochExecutionTranche, ) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); - for tranche in self.tranches.iter() { + let mut res = Vec::with_capacity(self.tranches.deref().len()); + for tranche in self.tranches.deref().iter() { let r = f(tranche)?; res.push(r) } @@ -1186,7 +1219,7 @@ where &mut EpochExecutionTranche, ) -> Result, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); for tranche in self.tranches.iter_mut() { let r = f(tranche)?; res.push(r) @@ -1206,8 +1239,8 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); - let iter = self.tranches.iter().zip(with.into_iter()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); + let iter = self.tranches.deref().iter().zip(with.into_iter()); for (tranche, w) in iter { let r = f(tranche, w)?; @@ -1229,7 +1262,7 @@ where ) -> Result, I: IntoIterator, { - let mut res = Vec::with_capacity(self.tranches.len()); + let mut res = Vec::with_capacity(self.tranches.deref().len()); let iter = self.tranches.iter_mut().zip(with.into_iter()); for (tranche, w) in iter { @@ -1242,12 +1275,13 @@ where } /// Business logic implementations for `EpochExecutionTranches` -impl - EpochExecutionTranches +impl + EpochExecutionTranches where Balance: Zero + Copy + BaseArithmetic + Unsigned + From, Weight: Copy + From, BalanceRatio: Copy, + MaxTranches: Get, { pub fn prices(&self) -> Vec { self.tranches.iter().map(|tranche| tranche.price).collect() diff --git a/pallets/restricted-tokens/src/lib.rs b/pallets/restricted-tokens/src/lib.rs index 9c78b98a47..abcebd3bd2 100644 --- a/pallets/restricted-tokens/src/lib.rs +++ b/pallets/restricted-tokens/src/lib.rs @@ -211,7 +211,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::event] diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index bf5ef23073..c20ec815d8 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -913,7 +913,8 @@ impl pallet_collator_selection::Config for Runtime { } parameter_types! { - #[derive(Debug, Eq, PartialEq, scale_info::TypeInfo, Clone)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, PartialOrd, scale_info::TypeInfo, Clone)] + #[cfg_attr(feature = "std", derive(frame_support::Serialize, frame_support::Deserialize))] pub const MaxTranches: u32 = 5; // How much time should lapse before a tranche investor can be removed @@ -928,10 +929,12 @@ impl pallet_permissions::Config for Runtime { type AdminOrigin = EnsureRootOr; type Editors = Editors; type MaxRolesPerScope = MaxRolesPerPool; + type MaxTranches = MaxTranches; type Role = Role; type RuntimeEvent = RuntimeEvent; type Scope = PermissionScope; - type Storage = PermissionRoles, MinDelay, TrancheId, Moment>; + type Storage = + PermissionRoles, MinDelay, TrancheId, MaxTranches, Moment>; type WeightInfo = weights::pallet_permissions::WeightInfo; } @@ -1253,6 +1256,7 @@ impl PoolUpdateGuard for UpdateGuard { TrancheWeight, TrancheId, PoolId, + MaxTranches, >; type ScheduledUpdateDetails = ScheduledUpdateDetails< Rate, @@ -1608,12 +1612,12 @@ 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) } - fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>{ + fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>{ let pool = pallet_pool_system::Pool::::get(pool_id)?; let epoch_execution_info = pallet_pool_system::EpochExecution::::get(pool_id)?; pallet_pool_system::Pallet::::score_solution( diff --git a/runtime/common/src/apis/pools.rs b/runtime/common/src/apis/pools.rs index 958b4bdf44..5ba5a6e474 100644 --- a/runtime/common/src/apis/pools.rs +++ b/runtime/common/src/apis/pools.rs @@ -16,6 +16,7 @@ use pallet_pool_system::{ EpochSolution, }; use sp_api::decl_runtime_apis; +use sp_runtime::traits::Get; use sp_std::vec::Vec; decl_runtime_apis! { @@ -23,17 +24,18 @@ decl_runtime_apis! { /// /// Note: The runtime api is pallet specific, while the RPC methods /// are more focused on domain-specific logic - pub trait PoolsApi + pub trait PoolsApi where PoolId: Codec, TrancheId: Codec, Balance: Codec, Currency: Codec, BalanceRatio: Codec, + MaxTranches: Codec + Get, { fn currency(pool_id: PoolId) -> Option; - fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>; + fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>; fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc) -> Option; diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 08720fadfb..a4f488c62d 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -1053,6 +1053,7 @@ impl PoolUpdateGuard for UpdateGuard { TrancheWeight, TrancheId, PoolId, + MaxTranches, >; type ScheduledUpdateDetails = ScheduledUpdateDetails< Rate, @@ -1276,7 +1277,8 @@ impl pallet_loans::Config for Runtime { } parameter_types! { - #[derive(Debug, Eq, PartialEq, scale_info::TypeInfo, Clone)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, PartialOrd, scale_info::TypeInfo, Clone)] + #[cfg_attr(feature = "std", derive(frame_support::Serialize, frame_support::Deserialize))] pub const MaxTranches: u32 = 5; // How much time should lapse before a tranche investor can be removed @@ -1291,10 +1293,12 @@ impl pallet_permissions::Config for Runtime { type AdminOrigin = EnsureRootOr; type Editors = Editors; type MaxRolesPerScope = MaxRolesPerPool; + type MaxTranches = MaxTranches; type Role = Role; type RuntimeEvent = RuntimeEvent; type Scope = PermissionScope; - type Storage = PermissionRoles, MinDelay, TrancheId, Moment>; + type Storage = + PermissionRoles, MinDelay, TrancheId, MaxTranches, Moment>; type WeightInfo = weights::pallet_permissions::WeightInfo; } @@ -1928,12 +1932,12 @@ 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) } - fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>{ + fn inspect_epoch_solution(pool_id: PoolId, solution: Vec) -> Option>{ let pool = pallet_pool_system::Pool::::get(pool_id)?; let epoch_execution_info = pallet_pool_system::EpochExecution::::get(pool_id)?; pallet_pool_system::Pallet::::score_solution( diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index 6264335a09..f62f62fa61 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -269,7 +269,7 @@ fn encoded_ethereum_xcm_add_pool() { interior: X1(Parachain(1000)), }; // 38 is the pallet index, 0 is the `transact` extrinsic index. - let ethereum_xcm_transact_call_index = vec![38, 0]; + let ethereum_xcm_transact_call_index = BoundedVec::truncate_from(vec![38, 0]); let contract_address = H160::from( <[u8; 20]>::from_hex("cE0Cb9BB900dfD0D378393A041f3abAb6B182882").expect("Decoding failed"), ); @@ -360,7 +360,7 @@ mod utils { .clone() .try_into() .expect("Bad xcm version"), - ethereum_xcm_transact_call_index: vec![38, 0], + ethereum_xcm_transact_call_index: BoundedVec::truncate_from(vec![38, 0]), contract_address: H160::from( <[u8; 20]>::from_hex("cE0Cb9BB900dfD0D378393A041f3abAb6B182882") .expect("Invalid address"), diff --git a/src/rpc/pools.rs b/src/rpc/pools.rs index 6237cffce7..53df0bf678 100644 --- a/src/rpc/pools.rs +++ b/src/rpc/pools.rs @@ -9,12 +9,18 @@ use pallet_pool_system::{ use runtime_common::apis::PoolsApi as PoolsRuntimeApi; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Get}, +}; use crate::rpc::{invalid_params_error, runtime_error}; #[rpc(client, server)] -pub trait PoolsApi { +pub trait PoolsApi +where + MaxTranches: Get, +{ #[method(name = "pools_currency")] fn currency(&self, poold_id: PoolId, at: Option) -> RpcResult; @@ -24,7 +30,7 @@ pub trait PoolsApi, at: Option, - ) -> RpcResult>; + ) -> RpcResult>; #[method(name = "pools_trancheTokenPrice")] fn tranche_token_price( @@ -75,17 +81,19 @@ impl Pools { } } -impl - PoolsApiServer for Pools +impl + PoolsApiServer + for Pools where Block: BlockT, C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - C::Api: PoolsRuntimeApi, + C::Api: PoolsRuntimeApi, Balance: Codec + Copy, PoolId: Codec + Copy + Debug, TrancheId: Codec + Clone + Debug, Currency: Codec, BalanceRatio: Codec, + MaxTranches: Codec + Get, { fn currency(&self, pool_id: PoolId, at: Option) -> RpcResult { let api = self.client.runtime_api(); @@ -105,7 +113,7 @@ where pool_id: PoolId, solution: Vec, at: Option, - ) -> RpcResult> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at = if let Some(hash) = at { BlockId::hash(hash)