From a03f741cc3b9d007167380cfcd5fd171e9108fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Mu=C3=B1oz=20Mart=C3=ADn?= Date: Tue, 6 Jun 2023 17:00:45 +0200 Subject: [PATCH] Loans: Add oracles to development runtime (#1377) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add needed utilities to work with oracles * added to oracle and data-collector to development runtime * get compile it with tuples-96 feature * add pallet-membershipt for oracle pricesĀ· * workaround for initializing oracles * new CombineData, fix warnings, minor PR comments * fix taplo fmt * fix oracle benchmarking * simplify benchmarks * mocking members trait * finally benchmarks fixed * Adapt pool number * reduce benchmarking time * add OracleKey type * correct benchmarking * fix cargo versions * taplo fmt * minor constant reorganization * fix minor issue * fix benchmarks * simplify benchmark configuration * minor change * add minor comment --- Cargo.lock | 8 ++ libs/mocks/Cargo.toml | 3 + libs/mocks/src/data.rs | 20 +++++ libs/primitives/src/lib.rs | 3 - libs/traits/src/lib.rs | 1 + libs/types/src/ids.rs | 2 +- libs/types/src/lib.rs | 1 + libs/types/src/oracles.rs | 36 ++++++++ pallets/data-collector/Cargo.toml | 14 +++ pallets/data-collector/src/lib.rs | 38 +++++++-- pallets/loans-ref/Cargo.toml | 5 +- pallets/loans-ref/src/benchmarking.rs | 27 ++++-- pallets/loans-ref/src/lib.rs | 1 - pallets/loans-ref/src/mock.rs | 1 + pallets/loans-ref/src/util.rs | 13 +++ runtime/altair/src/lib.rs | 2 +- runtime/centrifuge/src/lib.rs | 2 +- runtime/common/Cargo.toml | 7 ++ runtime/common/src/lib.rs | 118 ++++++++++++++++++++++++++ runtime/development/Cargo.toml | 15 +++- runtime/development/src/lib.rs | 86 ++++++++++++++++--- 21 files changed, 367 insertions(+), 36 deletions(-) create mode 100644 libs/types/src/oracles.rs diff --git a/Cargo.lock b/Cargo.lock index ce9d8352c2..d733899f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1217,6 +1217,7 @@ dependencies = [ "frame-support", "frame-system", "mock-builder", + "orml-traits", "parity-scale-codec 3.4.0", "scale-info", "sp-core", @@ -2620,6 +2621,7 @@ dependencies = [ "hex-literal 0.3.4", "moonbeam-relay-encoder", "orml-asset-registry", + "orml-oracle", "orml-tokens", "orml-traits", "orml-xcm", @@ -2639,6 +2641,7 @@ dependencies = [ "pallet-connectors", "pallet-crowdloan-claim", "pallet-crowdloan-reward", + "pallet-data-collector", "pallet-democracy", "pallet-elections-phragmen", "pallet-ethereum", @@ -2652,6 +2655,7 @@ dependencies = [ "pallet-keystore", "pallet-liquidity-rewards", "pallet-loans-ref", + "pallet-membership", "pallet-migration-manager", "pallet-multisig", "pallet-nft", @@ -7091,6 +7095,7 @@ name = "pallet-data-collector" version = "1.0.0" dependencies = [ "cfg-traits", + "frame-benchmarking", "frame-support", "frame-system", "orml-oracle", @@ -7478,6 +7483,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "orml-traits", "pallet-balances", "pallet-interest-accrual", "pallet-timestamp", @@ -10680,11 +10686,13 @@ dependencies = [ "frame-support", "frame-system", "hex-literal 0.2.2", + "orml-oracle", "orml-traits", "pallet-anchors", "pallet-authorship", "pallet-balances", "pallet-base-fee", + "pallet-data-collector", "pallet-ethereum", "pallet-evm", "pallet-evm-chain-id", diff --git a/libs/mocks/Cargo.toml b/libs/mocks/Cargo.toml index ea038d1de1..4791a5e95a 100644 --- a/libs/mocks/Cargo.toml +++ b/libs/mocks/Cargo.toml @@ -23,6 +23,8 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f cfg-primitives = { path = "../primitives", default-features = false } cfg-traits = { path = "../traits", default-features = false } cfg-types = { path = "../types", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } + mock-builder = { path = "../../libs/mock-builder" } [features] @@ -39,6 +41,7 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", + "orml-traits/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", diff --git a/libs/mocks/src/data.rs b/libs/mocks/src/data.rs index 045fe47525..cc84dec5bb 100644 --- a/libs/mocks/src/data.rs +++ b/libs/mocks/src/data.rs @@ -3,6 +3,7 @@ pub mod pallet { use cfg_traits::data::{DataCollection, DataRegistry}; use frame_support::pallet_prelude::*; use mock_builder::{execute_call, register_call}; + use orml_traits::{DataFeeder, DataProvider}; #[pallet::config] pub trait Config: frame_system::Config { @@ -10,6 +11,7 @@ pub mod pallet { type CollectionId; type Collection: DataCollection; type Data; + type DataElem; #[cfg(feature = "runtime-benchmarks")] type MaxCollectionSize: Get; } @@ -46,6 +48,12 @@ pub mod pallet { ) { register_call!(move |(a, b)| f(a, b)); } + + pub fn mock_feed_value( + f: impl Fn(T::AccountId, T::DataId, T::DataElem) -> DispatchResult + 'static, + ) { + register_call!(move |(a, b, c)| f(a, b, c)); + } } impl DataRegistry for Pallet { @@ -71,6 +79,18 @@ pub mod pallet { } } + impl DataProvider for Pallet { + fn get(a: &T::DataId) -> Option { + execute_call!(a) + } + } + + impl DataFeeder for Pallet { + fn feed_value(a: T::AccountId, b: T::DataId, c: T::DataElem) -> DispatchResult { + execute_call!((a, b, c)) + } + } + #[cfg(feature = "std")] pub mod util { use super::*; diff --git a/libs/primitives/src/lib.rs b/libs/primitives/src/lib.rs index e2432805a8..25e2f78bfe 100644 --- a/libs/primitives/src/lib.rs +++ b/libs/primitives/src/lib.rs @@ -175,9 +175,6 @@ pub mod types { /// A representation of a loan identifier pub type LoanId = u64; - - /// A representation of a price identifier - pub type PriceId = u64; } /// Common constants for all runtimes diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index 7ebc57650f..96f4c370c8 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -41,6 +41,7 @@ pub mod ops; /// Traits related to rewards. pub mod rewards; +/// Traits related to data registry & collections. pub mod data; /// A trait used for loosely coupling the claim pallet with a reward mechanism. diff --git a/libs/types/src/ids.rs b/libs/types/src/ids.rs index 8f20fba12f..97897941c3 100644 --- a/libs/types/src/ids.rs +++ b/libs/types/src/ids.rs @@ -24,7 +24,6 @@ impl TypeId for InvestmentAccount { // Pallet-Ids that define pallets accounts pub const POOLS_PALLET_ID: PalletId = PalletId(*b"roc/pool"); -pub const LOANS_PALLET_ID: PalletId = PalletId(*b"roc/loan"); pub const CHAIN_BRIDGE_PALLET_ID: PalletId = PalletId(*b"chnbrdge"); pub const CLAIMS_PALLET_ID: PalletId = PalletId(*b"p/claims"); pub const CROWDLOAN_REWARD_PALLET_ID: PalletId = PalletId(*b"cc/rewrd"); @@ -33,6 +32,7 @@ pub const TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); pub const NFT_SALES_PALLET_ID: PalletId = PalletId(*b"pal/nfts"); pub const STAKE_POT_PALLET_ID: PalletId = PalletId(*b"PotStake"); pub const BLOCK_REWARDS_PALLET_ID: PalletId = PalletId(*b"cfg/blrw"); +pub const PRICE_ORACLE_PALLET_ID: PalletId = PalletId(*b"or/price"); // Other ids pub const CHAIN_BRIDGE_HASH_ID: [u8; 13] = *b"cent_nft_hash"; diff --git a/libs/types/src/lib.rs b/libs/types/src/lib.rs index 29e4b34855..13fa97a624 100644 --- a/libs/types/src/lib.rs +++ b/libs/types/src/lib.rs @@ -24,6 +24,7 @@ pub mod fixed_point; pub mod ids; pub mod investments; pub mod locations; +pub mod oracles; pub mod orders; pub mod permissions; pub mod time; diff --git a/libs/types/src/oracles.rs b/libs/types/src/oracles.rs new file mode 100644 index 0000000000..bfde9ab484 --- /dev/null +++ b/libs/types/src/oracles.rs @@ -0,0 +1,36 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::RuntimeDebug; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +/// [ISIN](https://en.wikipedia.org/wiki/International_Securities_Identification_Number) format. +pub type Isin = [u8; 12]; + +/// A representation of an oracle price identifier +#[derive( + Encode, + Decode, + Clone, + Copy, + PartialOrd, + Ord, + PartialEq, + Eq, + TypeInfo, + RuntimeDebug, + MaxEncodedLen, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum OracleKey { + Isin(Isin), +} + +#[cfg(feature = "runtime-benchmarks")] +impl From for OracleKey { + fn from(value: u32) -> Self { + // Any u32 value always fits into 12 bytes + let isin = Isin::try_from(&(value as u128).to_be_bytes()[0..12]).unwrap(); + OracleKey::Isin(isin) + } +} diff --git a/pallets/data-collector/Cargo.toml b/pallets/data-collector/Cargo.toml index bf3749bbcc..a215bd899b 100644 --- a/pallets/data-collector/Cargo.toml +++ b/pallets/data-collector/Cargo.toml @@ -24,6 +24,9 @@ orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-li cfg-traits = { path = "../../libs/traits", default-features = false } +# Optionals for benchmarking +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } + [dev-dependencies] sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } @@ -43,7 +46,18 @@ std = [ "sp-std/std", "cfg-traits/std", "orml-traits/std", + "frame-benchmarking/std", ] runtime-benchmarks = [ + "frame-benchmarking", "cfg-traits/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", + "cfg-traits/try-runtime", ] diff --git a/pallets/data-collector/src/lib.rs b/pallets/data-collector/src/lib.rs index ff4ca00925..b034f4a7a6 100644 --- a/pallets/data-collector/src/lib.rs +++ b/pallets/data-collector/src/lib.rs @@ -28,10 +28,10 @@ mod tests; pub mod pallet { use cfg_traits::data::{DataCollection, DataRegistry}; use frame_support::{pallet_prelude::*, storage::bounded_btree_map::BoundedBTreeMap}; - use orml_traits::{DataProviderExtended, OnNewData}; + use orml_traits::{DataFeeder, DataProvider, DataProviderExtended, OnNewData}; use sp_runtime::{ traits::{EnsureAddAssign, EnsureSubAssign}, - DispatchError, + DispatchError, DispatchResult, }; type DataValueOf = (>::Data, >::Moment); @@ -130,8 +130,10 @@ pub mod pallet { .map_err(|_| Error::::MaxCollectionNumber)?; Collection::::try_mutate(collection_id, |collection| { + let data = + >::get(data_id)?; collection - .try_insert(data_id.clone(), Self::get(data_id)?) + .try_insert(data_id.clone(), data) .map(|_| ()) .map_err(|_| Error::::MaxCollectionSize.into()) }) @@ -166,9 +168,8 @@ pub mod pallet { // for Data values. for collection_id in Listening::::get(data_id).keys() { Collection::::mutate(collection_id, |collection| { - if let (Some(value), Ok(new_value)) = - (collection.get_mut(data_id), Self::get(data_id)) - { + let data = >::get(data_id); + if let (Some(value), Ok(new_value)) = (collection.get_mut(data_id), data) { *value = new_value; } }); @@ -176,6 +177,31 @@ pub mod pallet { } } + // This implementation can be removed once: + // be merged, + // and consecuently, get() call methods simplified. + impl, I: 'static> DataProvider for Pallet + where + T::DataProvider: DataProvider, + { + fn get(key: &T::DataId) -> Option { + T::DataProvider::get(key) + } + } + + impl, I: 'static> DataFeeder for Pallet + where + T::DataProvider: DataFeeder, + { + fn feed_value( + account_id: T::AccountId, + data_id: T::DataId, + data: T::Data, + ) -> DispatchResult { + T::DataProvider::feed_value(account_id, data_id, data) + } + } + /// A collection cached in memory pub struct CachedCollection, I: 'static = ()>( BoundedBTreeMap, T::MaxCollectionSize>, diff --git a/pallets/loans-ref/Cargo.toml b/pallets/loans-ref/Cargo.toml index 497a57ffb0..11ca0eb444 100644 --- a/pallets/loans-ref/Cargo.toml +++ b/pallets/loans-ref/Cargo.toml @@ -23,10 +23,11 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f cfg-primitives = { path = "../../libs/primitives", default-features = false } cfg-traits = { path = "../../libs/traits", default-features = false } cfg-types = { path = "../../libs/types", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } strum = { version = "0.24", default-features = false, features = ["derive"] } -# Optionals for benchamarking +# Optionals for benchmarking frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } # Used for migrations (no longer needed once migratios is done) @@ -61,6 +62,7 @@ std = [ "frame-benchmarking/std", "sp-io/std", "strum/std", + "orml-traits/std", ] runtime-benchmarks = [ "frame-benchmarking", @@ -76,6 +78,7 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", + "sp-runtime/try-runtime", "cfg-primitives/try-runtime", "cfg-traits/try-runtime", "cfg-types/try-runtime", diff --git a/pallets/loans-ref/src/benchmarking.rs b/pallets/loans-ref/src/benchmarking.rs index 3a51c0365a..b37a955096 100644 --- a/pallets/loans-ref/src/benchmarking.rs +++ b/pallets/loans-ref/src/benchmarking.rs @@ -29,6 +29,7 @@ use frame_support::{ }, }; use frame_system::RawOrigin; +use orml_traits::DataFeeder; use sp_arithmetic::FixedPointNumber; use sp_runtime::traits::{Get, One, Zero}; use sp_std::{time::Duration, vec}; @@ -75,6 +76,7 @@ where T::Pool: PoolBenchmarkHelper, AccountId = T::AccountId, Balance = T::Balance>, PriceCollectionOf: DataCollection>, + T::PriceRegistry: DataFeeder, { #[cfg(test)] fn config_mocks() { @@ -90,6 +92,7 @@ where MockPools::mock_deposit(|_, _, _| Ok(())); MockPools::mock_benchmark_create_pool(|_, _| {}); MockPools::mock_benchmark_give_ausd(|_, _| {}); + MockPrices::mock_feed_value(|_, _, _| Ok(())); MockPrices::mock_register_id(|_, _| Ok(())); MockPrices::mock_collection(|_| MockDataCollection::new(|_| Ok((0, 0)))); } @@ -228,7 +231,12 @@ where } for i in 0..MaxCollectionSizeOf::::get() { - let price_id = T::PriceId::from(i + 1); + let price_id = i.into(); + // This account is different in each iteration because of how oracles works. + // This restriction no longer exists once + // https://github.com/open-web3-stack/open-runtime-module-library/pull/920 is merged + let feeder = account("feeder", i, 0); + T::PriceRegistry::feed_value(feeder, price_id, 0.into()).unwrap(); T::PriceRegistry::register_id(&price_id, &pool_id).unwrap(); } @@ -240,6 +248,10 @@ where pool_id } + + fn max_active_loans() -> u32 { + T::MaxActiveLoansPerPool::get().min(10) + } } benchmarks! { @@ -252,6 +264,7 @@ benchmarks! { T::PriceId: From, T::Pool: PoolBenchmarkHelper, AccountId = T::AccountId, Balance = T::Balance>, PriceCollectionOf: DataCollection>, + T::PriceRegistry: DataFeeder, } create { @@ -265,7 +278,7 @@ benchmarks! { }: _(RawOrigin::Signed(borrower), pool_id, loan_info) borrow { - let n in 1..T::MaxActiveLoansPerPool::get() - 1; + let n in 1..Helper::::max_active_loans() - 1; let borrower = account("borrower", 0, 0); let pool_id = Helper::::initialize_active_state(n); @@ -274,7 +287,7 @@ benchmarks! { }: _(RawOrigin::Signed(borrower), pool_id, loan_id, 10.into()) repay { - let n in 1..T::MaxActiveLoansPerPool::get() - 1; + let n in 1..Helper::::max_active_loans() - 1; let borrower = account("borrower", 0, 0); let pool_id = Helper::::initialize_active_state(n); @@ -284,7 +297,7 @@ benchmarks! { }: _(RawOrigin::Signed(borrower), pool_id, loan_id, 10.into(), 0.into()) write_off { - let n in 1..T::MaxActiveLoansPerPool::get() - 1; + let n in 1..Helper::::max_active_loans() - 1; let borrower = account("borrower", 0, 0); let pool_id = Helper::::initialize_active_state(n); @@ -296,7 +309,7 @@ benchmarks! { }: _(RawOrigin::Signed(borrower), pool_id, loan_id) admin_write_off { - let n in 1..T::MaxActiveLoansPerPool::get() - 1; + let n in 1..Helper::::max_active_loans() - 1; let loan_admin = account("loan_admin", 0, 0); let pool_id = Helper::::initialize_active_state(n); @@ -307,7 +320,7 @@ benchmarks! { }: _(RawOrigin::Signed(loan_admin), pool_id, loan_id, T::Rate::zero(), T::Rate::zero()) close { - let n in 1..T::MaxActiveLoansPerPool::get() - 1; + let n in 1..Helper::::max_active_loans() - 1; let borrower = account("borrower", 0, 0); let pool_id = Helper::::initialize_active_state(n); @@ -325,7 +338,7 @@ benchmarks! { }: _(RawOrigin::Signed(pool_admin), pool_id, policy) update_portfolio_valuation { - let n in 1..T::MaxActiveLoansPerPool::get(); + let n in 1..Helper::::max_active_loans(); let borrower = account("borrower", 0, 0); let pool_id = Helper::::initialize_active_state(n); diff --git a/pallets/loans-ref/src/lib.rs b/pallets/loans-ref/src/lib.rs index 54f201e205..e82b7bf11c 100644 --- a/pallets/loans-ref/src/lib.rs +++ b/pallets/loans-ref/src/lib.rs @@ -162,7 +162,6 @@ pub mod pallet { type PriceId: Parameter + Member + MaybeSerializeDeserialize - + Default + TypeInfo + Copy + MaxEncodedLen; diff --git a/pallets/loans-ref/src/mock.rs b/pallets/loans-ref/src/mock.rs index f101418a13..9661bfbfee 100644 --- a/pallets/loans-ref/src/mock.rs +++ b/pallets/loans-ref/src/mock.rs @@ -187,6 +187,7 @@ impl pallet_mock_data::Config for Runtime { type Collection = pallet_mock_data::util::MockDataCollection; type CollectionId = PoolId; type Data = Result<(Balance, Moment), DispatchError>; + type DataElem = Balance; type DataId = PriceId; #[cfg(feature = "runtime-benchmarks")] type MaxCollectionSize = MaxActiveLoansPerPool; diff --git a/pallets/loans-ref/src/util.rs b/pallets/loans-ref/src/util.rs index b4b3ced601..6935b9dd6f 100644 --- a/pallets/loans-ref/src/util.rs +++ b/pallets/loans-ref/src/util.rs @@ -12,6 +12,7 @@ // GNU General Public License for more details. use cfg_traits::data::{DataCollection, DataRegistry}; +use orml_traits::{DataFeeder, DataProvider}; use sp_runtime::{DispatchError, DispatchResult}; use sp_std::marker::PhantomData; @@ -45,6 +46,18 @@ impl DataRegistry> for NoPriceRegistry { } } +impl DataProvider for NoPriceRegistry { + fn get(_: &T::PriceId) -> Option { + None + } +} + +impl DataFeeder for NoPriceRegistry { + fn feed_value(_: T::AccountId, _: T::PriceId, _: T::Balance) -> DispatchResult { + Err(DEFAULT_ERR) + } +} + pub struct NoPriceCollection(PhantomData); impl DataCollection for NoPriceCollection { diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index a73e6066c9..145bebb953 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1256,7 +1256,7 @@ impl pallet_loans_ref::Config for Runtime { type NonFungible = Uniques; type Permissions = Permissions; type Pool = PoolSystem; - type PriceId = PriceId; + type PriceId = u32; type PriceRegistry = pallet_loans_ref::util::NoPriceRegistry; type Rate = Rate; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index 7fccfc2c55..1bf3e63cd8 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -1573,7 +1573,7 @@ impl pallet_loans_ref::Config for Runtime { type NonFungible = Uniques; type Permissions = Permissions; type Pool = PoolSystem; - type PriceId = PriceId; + type PriceId = u32; type PriceRegistry = pallet_loans_ref::util::NoPriceRegistry; type Rate = Rate; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index 128588751d..7077c110bb 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -30,6 +30,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.38" } # ORML dependencies +orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } # Frontier dependencies @@ -44,6 +45,7 @@ cfg-primitives = { path = "../../libs/primitives", default-features = false } cfg-types = { path = "../../libs/types", default-features = false } cfg-utils = { path = "../../libs/utils", default-features = false } pallet-anchors = { path = "../../pallets/anchors", default-features = false } +pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-pool-system = { path = "../../pallets/pool-system", default-features = false } [dev-dependencies] @@ -77,7 +79,9 @@ std = [ "cfg-primitives/std", "cfg-utils/std", "orml-traits/std", + "orml-oracle/std", "pallet-pool-system/std", + "pallet-data-collector/std", "serde/std", "scale-info/std", "xcm/std", @@ -92,6 +96,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-pool-system/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", + "pallet-data-collector/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-ethereum/runtime-benchmarks", @@ -106,10 +111,12 @@ try-runtime = [ "cfg-utils/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", + "orml-oracle/try-runtime", "pallet-anchors/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", "pallet-pool-system/try-runtime", + "pallet-data-collector/try-runtime", "pallet-treasury/try-runtime", "cfg-primitives/try-runtime", "pallet-evm/try-runtime", diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index ee5754988d..9a138d4ca6 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -22,6 +22,17 @@ pub mod account_conversion; pub mod apis; pub mod evm; +#[macro_export] +macro_rules! production_or_benchmark { + ($production:expr, $benchmark:expr) => {{ + if cfg!(feature = "runtime-benchmarks") { + $benchmark + } else { + $production + } + }}; +} + pub mod xcm_fees { use cfg_primitives::{constants::currency_decimals, types::Balance}; use frame_support::weights::constants::{ExtrinsicBaseWeight, WEIGHT_REF_TIME_PER_SECOND}; @@ -273,3 +284,110 @@ pub mod xcm { } } } + +pub mod oracle { + use cfg_primitives::types::{AccountId, Balance, Moment}; + use cfg_types::oracles::OracleKey; + use orml_traits::{CombineData, DataFeeder, DataProvider, DataProviderExtended}; + use sp_runtime::DispatchResult; + use sp_std::{marker::PhantomData, vec::Vec}; + + type OracleValue = orml_oracle::TimestampedValue; + + /// Always choose the last updated value in case of several values. + pub struct LastOracleValue; + + #[cfg(not(feature = "runtime-benchmarks"))] + impl CombineData for LastOracleValue { + fn combine_data( + _: &OracleKey, + values: Vec, + _: Option, + ) -> Option { + values + .into_iter() + .max_by(|v1, v2| v1.timestamp.cmp(&v2.timestamp)) + } + } + + /// A provider that maps an `OracleValue` into a tuple `(Balance, Moment)`. + /// This aux type is forced because of + /// and can be removed once they fix this. + pub struct DataProviderBridge(PhantomData); + + impl> + DataProviderExtended for DataProviderBridge + { + fn get_no_op(key: &OracleKey) -> Option<(Balance, Moment)> { + OrmlOracle::get_no_op(key).map(|OracleValue { value, timestamp }| (value, timestamp)) + } + + fn get_all_values() -> Vec<(OracleKey, Option<(Balance, Moment)>)> { + OrmlOracle::get_all_values() + .into_iter() + .map(|elem| { + ( + elem.0, + elem.1 + .map(|OracleValue { value, timestamp }| (value, timestamp)), + ) + }) + .collect() + } + } + + impl> DataProvider + for DataProviderBridge + { + fn get(key: &OracleKey) -> Option { + OrmlOracle::get(key) + } + } + + impl> + DataFeeder for DataProviderBridge + { + fn feed_value(who: AccountId, key: OracleKey, value: Balance) -> DispatchResult { + OrmlOracle::feed_value(who, key, value) + } + } + + /// This is used for feeding the oracle from the data-collector in + /// benchmarks. + /// It can be removed once is merged. + #[cfg(feature = "runtime-benchmarks")] + pub mod benchmarks_util { + use frame_support::traits::SortedMembers; + use sp_std::vec::Vec; + + use super::*; + + impl CombineData for LastOracleValue { + fn combine_data( + _: &OracleKey, + _: Vec, + _: Option, + ) -> Option { + Some(OracleValue { + value: 0, + timestamp: 0, + }) + } + } + + pub struct Members; + + impl SortedMembers for Members { + fn sorted_members() -> Vec { + // We do not want members for benchmarking + Vec::default() + } + + fn contains(_: &AccountId) -> bool { + // We want to mock the member permission for benchmark + // Allowing any member + true + } + } + } +} diff --git a/runtime/development/Cargo.toml b/runtime/development/Cargo.toml index 1167177365..0cee8266ae 100644 --- a/runtime/development/Cargo.toml +++ b/runtime/development/Cargo.toml @@ -55,7 +55,9 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features # frame dependencies frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38", features = [ + "tuples-96", +] } # tuples feature can be remove on 0.9.42 frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -67,6 +69,7 @@ pallet-collective = { git = "https://github.com/paritytech/substrate", default-f pallet-democracy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-elections-phragmen = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-identity = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } +pallet-membership = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-preimage = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.38" } @@ -84,6 +87,7 @@ pallet-vesting = { git = "https://github.com/paritytech/substrate", default-feat # orml pallets orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } +orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } orml-xcm = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" } @@ -116,6 +120,7 @@ pallet-collator-allowlist = { path = "../../pallets/collator-allowlist", default pallet-connectors = { path = "../../pallets/connectors", default-features = false } pallet-crowdloan-claim = { path = "../../pallets/crowdloan-claim", default-features = false } pallet-crowdloan-reward = { path = "../../pallets/crowdloan-reward", default-features = false } +pallet-data-collector = { path = "../../pallets/data-collector", default-features = false } pallet-fees = { path = "../../pallets/fees", default-features = false } pallet-interest-accrual = { path = "../../pallets/interest-accrual", default-features = false } pallet-investments = { path = "../../pallets/investments", default-features = false } @@ -168,6 +173,7 @@ std = [ "orml-asset-registry/std", "orml-tokens/std", "orml-xtokens/std", + "orml-oracle/std", "pallet-anchors/std", "pallet-aura/std", "pallet-authorship/std", @@ -182,6 +188,7 @@ std = [ "pallet-connectors/std", "pallet-crowdloan-claim/std", "pallet-crowdloan-reward/std", + "pallet-data-collector/std", "pallet-democracy/std", "pallet-elections-phragmen/std", "pallet-ethereum/std", @@ -197,6 +204,7 @@ std = [ "pallet-loans-ref/std", "pallet-migration-manager/std", "pallet-multisig/std", + "pallet-membership/std", "pallet-nft-sales/std", "pallet-nft/std", "pallet-permissions/std", @@ -271,6 +279,7 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-crowdloan-claim/runtime-benchmarks", "pallet-crowdloan-reward/runtime-benchmarks", + "pallet-data-collector/runtime-benchmarks", "pallet-ethereum/runtime-benchmarks", "pallet-evm/runtime-benchmarks", "pallet-fees/runtime-benchmarks", @@ -303,6 +312,7 @@ runtime-benchmarks = [ "pallet-elections-phragmen/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-membership/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", @@ -355,6 +365,7 @@ try-runtime = [ "orml-tokens/try-runtime", "orml-xcm/try-runtime", "orml-xtokens/try-runtime", + "orml-oracle/try-runtime", "pallet-anchors/try-runtime", "pallet-aura/try-runtime", "pallet-authorship/try-runtime", @@ -366,12 +377,14 @@ try-runtime = [ "pallet-collective/try-runtime", "pallet-crowdloan-claim/try-runtime", "pallet-crowdloan-reward/try-runtime", + "pallet-data-collector/try-runtime", "pallet-democracy/try-runtime", "pallet-elections-phragmen/try-runtime", "pallet-fees/try-runtime", "pallet-identity/try-runtime", "pallet-migration-manager/try-runtime", "pallet-multisig/try-runtime", + "pallet-membership/try-runtime", "pallet-nft/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 1309a6ed2d..80b798e6ca 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -32,7 +32,9 @@ use cfg_types::{ consts::pools::*, fee_keys::FeeKey, fixed_point::Rate, + ids::PRICE_ORACLE_PALLET_ID, locations::Location, + oracles::OracleKey, permissions::{ PermissionRoles, PermissionScope, PermissionedCurrencyRole, PoolRole, Role, UNION, }, @@ -1291,8 +1293,72 @@ impl pallet_xcm_transactor::Config for Runtime { } parameter_types! { - pub const MaxActiveLoansPerPool: u32 = 50; + pub const MaxActiveLoansPerPool: u32 = 1000; + pub const MaxRateCount: u32 = MaxActiveLoansPerPool::get(); + pub const MaxCollectionSize: u32 = MaxActiveLoansPerPool::get(); pub const MaxWriteOffPolicySize: u32 = 10; + pub const MaxPriceOracleMembers: u32 = 5; + pub const MaxHasDispatchedSize: u32 = production_or_benchmark!( + MaxPriceOracleMembers::get(), + // For benchmarking we need a number of members equals to the active loans. + // The benchmark distintion can be removed once + // be merged. + MaxActiveLoansPerPool::get() + ); + pub const MaxPoolsWithExternalPrices: u32 = 50; + pub RootOperatorOraclePrice: AccountId = PRICE_ORACLE_PALLET_ID.into_account_truncating(); +} + +impl pallet_membership::Config for Runtime { + type AddOrigin = EnsureRootOr; + type MaxMembers = MaxPriceOracleMembers; + type MembershipChanged = PriceOracle; + type MembershipInitialized = (); + type PrimeOrigin = EnsureRootOr; + type RemoveOrigin = EnsureRootOr; + type ResetOrigin = EnsureRootOr; + type RuntimeEvent = RuntimeEvent; + type SwapOrigin = EnsureRootOr; + type WeightInfo = pallet_membership::weights::SubstrateWeight; +} + +impl orml_oracle::Config for Runtime { + type CombineData = runtime_common::oracle::LastOracleValue; + type MaxHasDispatchedSize = MaxHasDispatchedSize; + #[cfg(not(feature = "runtime-benchmarks"))] + type Members = PriceOracleMembership; + // This can be removed once + // be merged. + #[cfg(feature = "runtime-benchmarks")] + type Members = runtime_common::oracle::benchmarks_util::Members; + type OnNewData = PriceCollector; + type OracleKey = OracleKey; + type OracleValue = Balance; + type RootOperatorAccountId = RootOperatorOraclePrice; + type RuntimeEvent = RuntimeEvent; + type Time = Timestamp; + type WeightInfo = (); +} + +impl pallet_data_collector::Config for Runtime { + type CollectionId = PoolId; + type Data = Balance; + type DataId = OracleKey; + type DataProvider = runtime_common::oracle::DataProviderBridge; + type MaxCollectionSize = MaxCollectionSize; + type MaxCollections = MaxPoolsWithExternalPrices; + type Moment = Moment; +} + +impl pallet_interest_accrual::Config for Runtime { + type Balance = Balance; + type InterestRate = Rate; + // TODO: This is a stopgap value until we can calculate it correctly with + // updated benchmarks. See #1024 + type MaxRateCount = MaxRateCount; + type RuntimeEvent = RuntimeEvent; + type Time = Timestamp; + type Weights = (); } impl pallet_loans_ref::Config for Runtime { @@ -1307,8 +1373,8 @@ impl pallet_loans_ref::Config for Runtime { type NonFungible = Uniques; type Permissions = Permissions; type Pool = PoolSystem; - type PriceId = PriceId; - type PriceRegistry = pallet_loans_ref::util::NoPriceRegistry; + type PriceId = OracleKey; + type PriceRegistry = PriceCollector; type Rate = Rate; type RuntimeEvent = RuntimeEvent; type Time = Timestamp; @@ -1490,17 +1556,6 @@ impl orml_asset_registry::Config for Runtime { type WeightInfo = (); } -impl pallet_interest_accrual::Config for Runtime { - type Balance = Balance; - type InterestRate = Rate; - // TODO: This is a stopgap value until we can calculate it correctly with - // updated benchmarks. See #1024 - type MaxRateCount = MaxActiveLoansPerPool; - type RuntimeEvent = RuntimeEvent; - type Time = Timestamp; - type Weights = (); -} - impl pallet_connectors::Config for Runtime { type AccountConverter = AccountConverter; type AdminOrigin = EnsureRoot; @@ -1830,6 +1885,7 @@ construct_runtime!( BlockRewardsBase: pallet_rewards::::{Pallet, Storage, Event, Config} = 110, BlockRewards: pallet_block_rewards::{Pallet, Call, Storage, Event, Config} = 111, TransferAllowList: pallet_transfer_allowlist::{Pallet, Call, Storage, Event} = 112, + PriceCollector: pallet_data_collector::{Pallet, Storage} = 113, // XCM XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 120, @@ -1844,6 +1900,8 @@ construct_runtime!( ChainBridge: chainbridge::{Pallet, Call, Storage, Event} = 151, OrmlAssetRegistry: orml_asset_registry::{Pallet, Storage, Call, Event, Config} = 152, OrmlXcm: orml_xcm::{Pallet, Storage, Call, Event} = 153, + PriceOracle: orml_oracle::{Pallet, Call, Storage, Event} = 154, + PriceOracleMembership: pallet_membership::{Pallet, Call, Storage, Event} = 155, // EVM pallets EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 160,