diff --git a/Cargo.lock b/Cargo.lock index 4bba996a..5530d761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3968,6 +3968,7 @@ dependencies = [ "pallet-briefs", "pallet-collator-selection", "pallet-collective", + "pallet-crowdfunding", "pallet-democracy", "pallet-deposits", "pallet-grants", @@ -6416,6 +6417,7 @@ dependencies = [ name = "pallet-crowdfunding" version = "0.1.0" dependencies = [ + "common-runtime", "common-types", "frame-benchmarking", "frame-support", diff --git a/pallets/crowdfunding/Cargo.toml b/pallets/crowdfunding/Cargo.toml index e69ae289..4ecaa1fe 100644 --- a/pallets/crowdfunding/Cargo.toml +++ b/pallets/crowdfunding/Cargo.toml @@ -27,6 +27,7 @@ pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "p orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.39", default-features = false } common-types = { path = "../../libs/common-types", default-features = false } +common-runtime = { path = "../../runtime/common", default-features = false} pallet-proposals = { path= "../proposals", default-features = false} pallet-deposits = {path= "../deposits", default-features = false } @@ -36,6 +37,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkad sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39"} pallet-proposals = { path= "../proposals"} common-types = { path = "../../libs/common-types"} +common-runtime = { path = "../../runtime/common"} sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39"} pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39"} orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.39" } @@ -57,8 +59,9 @@ std = [ "pallet-proposals/std", "sp-core/std", "pallet-identity/std", - "pallet-xcm/std" + "pallet-xcm/std", + "common-runtime/std", ] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "common-runtime/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/crowdfunding/src/benchmarking.rs b/pallets/crowdfunding/src/benchmarking.rs index 8ebdc38e..d95f9151 100644 --- a/pallets/crowdfunding/src/benchmarking.rs +++ b/pallets/crowdfunding/src/benchmarking.rs @@ -1,17 +1,16 @@ -//! Benchmarking setup for pallet-template +//! Benchmarking setup for pallet-crowdfunding use super::*; - use crate::Pallet as CrowdFunding; use common_types::CurrencyId; -use frame_benchmarking::v1::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::assert_ok; +use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::{assert_ok, sp_runtime::SaturatedConversion}; use frame_system::{EventRecord, RawOrigin}; use orml_traits::MultiCurrency; use pallet_proposals::ProposedMilestone; use sp_arithmetic::per_things::Percent; use sp_core::{Get, H256}; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{vec::Vec, collections::btree_map::BTreeMap}; benchmarks! { where_clause { @@ -19,14 +18,14 @@ benchmarks! { } create_crowdfund { - let caller: T::AccountId = whitelisted_caller(); + let caller: T::AccountId = create_funded_user::("initiator", 1, 100_000_000_000_000_000u128); let milestones = get_max_milestones::(); let required_funds = u32::MAX; let currency_id = CurrencyId::Native; let agg_hash = H256::from([10u8; 32]); let crowdfund_key = 0; // (Origin, agg_hash, ProposedMilestones, RequiredFunds, CurrencyId) - }: _(RawOrigin::Signed(whitelisted_caller()), agg_hash, milestones, required_funds.into(), CurrencyId::Native) + }: _(RawOrigin::Signed(caller.clone()), agg_hash, milestones, required_funds.into(), CurrencyId::Native) verify { assert_last_event::(Event::::CrowdFundCreated(caller, agg_hash, crowdfund_key, required_funds.into(), CurrencyId::Native).into()); } @@ -85,7 +84,7 @@ benchmarks! { contribute { let required_funds = u32::MAX; create_crowdfund_common::(required_funds); - let alice: T::AccountId = create_funded_user::("candidate", 1, 100_000); + let alice: T::AccountId = create_funded_user::("candidate", 1, 100_000_000_000_000_000u128); let caller: T::AccountId = whitelisted_caller(); let _ = CrowdFunding::::open_contributions(RawOrigin::Root.into(), 0); @@ -96,11 +95,11 @@ benchmarks! { } approve_crowdfund_for_milestone_submission { - let required_funds: u32 = 100_000u32; + let required_funds: u32 = u32::MAX; create_crowdfund_common::(required_funds); - let alice: T::AccountId = create_funded_user::("candidate", 1, required_funds.into()); - let _ = CrowdFunding::::open_contributions(RawOrigin::Root.into(), 0); - let _ = CrowdFunding::::contribute(RawOrigin::Signed(alice.clone()).into(), 0u32, required_funds.into()); + let alice: T::AccountId = create_funded_user::("candidate", 1, 100_000_000_000_000_000u128); + assert_ok!(CrowdFunding::::open_contributions(RawOrigin::Root.into(), 0)); + assert_ok!(CrowdFunding::::contribute(RawOrigin::Signed(alice.clone()).into(), 0u32, required_funds.into())); //(Origin, CrowdFundKey) }: _(RawOrigin::Root, 0) @@ -109,25 +108,23 @@ benchmarks! { } } -impl_benchmark_test_suite!(CrowdFunding, crate::mock::new_test_ext(), crate::mock::Test); - -fn create_funded_user( - string: &'static str, +pub fn create_funded_user( + seed: &'static str, n: u32, - balance_factor: u32, + balance_factor: u128, ) -> T::AccountId { - let user = account(string, n, 99); - let balance: BalanceOf = balance_factor.into(); - let _ = ::AccountId>>::deposit( - CurrencyId::Native, - &user, - balance, - ); + let user = account(seed, n, 0); + assert_ok!(::AccountId, + >>::deposit( + CurrencyId::Native, &user, balance_factor.saturated_into() + )); user } + fn create_crowdfund_common(required_funds: u32) -> T::AccountId { - let bob: T::AccountId = create_funded_user::("initiator", 1, 100_000_000); + let bob: T::AccountId = create_funded_user::("initiator", 1, 100_000_000_000_000_000u128); let milestones = get_max_milestones::(); let agg_hash = H256::from([20; 32]); @@ -174,3 +171,5 @@ where let EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); } + +impl_benchmark_test_suite!(CrowdFunding, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/pallets/crowdfunding/src/lib.rs b/pallets/crowdfunding/src/lib.rs index 291aa45b..816ef856 100644 --- a/pallets/crowdfunding/src/lib.rs +++ b/pallets/crowdfunding/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; -mod weights; +pub mod weights; #[cfg(test)] mod mock; @@ -26,6 +26,7 @@ pub mod pallet { use sp_arithmetic::per_things::Percent; use sp_core::H256; use sp_std::collections::btree_map::BTreeMap; + use pallet_deposits::traits::DepositHandler; pub type AccountIdOf = ::AccountId; pub type BalanceOf = @@ -46,6 +47,9 @@ pub mod pallet { pub type BoundedProposedMilestones = BoundedVec::MaxMilestonesPerCrowdFund>; + type StorageItemOf = <::DepositHandler as DepositHandler, AccountIdOf>>::StorageItem; + type DepositIdOf = <::DepositHandler as DepositHandler, AccountIdOf>>::DepositId; + pub type CrowdFundKey = u32; pub type MilestoneKey = u32; @@ -62,14 +66,26 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_identity::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; type MultiCurrency: MultiReservableCurrency, CurrencyId = CurrencyId>; + /// The length of a round in the system. type RoundExpiry: Get>; + /// The maximum number of crowdfund keys in a given round. type MaxKeysPerRound: Get; + /// The maximum number of contributors possible in a crowdfund. type MaxContributionsPerCrowdFund: Get; + /// The maximum number of milestones that is possible in a crowdfund. type MaxMilestonesPerCrowdFund: Get; + /// The maximum number of whitelist spots in a crowdfund. type MaxWhitelistPerCrowdFund: Get; + /// Define whether a decent identity is required when creating a crowdfund. type IsIdentityRequired: Get; + /// The authority responsible for governance actions. type AuthorityOrigin: EnsureOrigin; + /// The type that converts a crowdfund into a project and allows milestone submission. type IntoProposals: IntoProposal, BalanceOf, BlockNumberFor>; + /// The type responsible for handling storage deposits. + type DepositHandler: DepositHandler, AccountIdOf>; + /// The type that the deposit fee will be calculated from. + type CrowdFundStorageItem: Get>; type WeightInfo: WeightInfo; } @@ -79,13 +95,13 @@ pub mod pallet { /// Stores a list of crowdfunds. #[pallet::storage] - pub type CrowdFunds = StorageMap<_, Blake2_128, CrowdFundKey, CrowdFund, OptionQuery>; + pub type CrowdFunds = StorageMap<_, Blake2_128Concat, CrowdFundKey, CrowdFund, OptionQuery>; /// Stores the crowdfund keys that are expiring on a given block. /// Handled in the hooks, #[pallet::storage] pub type RoundsExpiring = - StorageMap<_, Blake2_128, BlockNumberFor, BoundedKeysPerRound, ValueQuery>; + StorageMap<_, Blake2_128Concat, BlockNumberFor, BoundedKeysPerRound, ValueQuery>; /// Tracks wether CrowdFunds are in a given round type. /// Key 1 : CrowdFundID @@ -94,15 +110,17 @@ pub mod pallet { #[pallet::storage] pub type CrowdFundsInRound = StorageDoubleMap< _, - Blake2_128, + Blake2_128Concat, CrowdFundKey, - Blake2_128, + Blake2_128Concat, RoundType, BlockNumberFor, ValueQuery, >; /// Tracks the whitelists of a given crowdfund. + /// MIGRATION FROM PROPOSALS REFACTOR? + /// PALLET PREFIX HAS CHANGED #[pallet::storage] #[pallet::getter(fn whitelist_spots)] pub type WhitelistSpots = @@ -167,12 +185,14 @@ pub mod pallet { IdentityNeeded, /// Below the minimum required funds. BelowMinimumRequiredFunds, - /// The crowdfund as already been converted to milestones. - CrowdFundAlreadyConverted, /// The crowdfund has already been cancelled. CrowdFundCancelled, /// The conversion to a Project has failed. CrowdFundConversionFailedGeneric, + /// You are trying to add too many whitelist spots. + WhiteListSpotLimitReached, + /// There are too many rounds inserted this block, please wait for the next on (6s) + TooManyRoundsInBlock, } #[pallet::call] @@ -217,17 +237,10 @@ pub mod pallet { agreement_hash: Option, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - if ::IsIdentityRequired::get() { - Self::ensure_identity_is_decent(&who)?; - } - + let crowdfund = CrowdFunds::::get(crowdfund_key).ok_or(Error::::CrowdFundDoesNotExist)?; ensure!(crowdfund.initiator == who, Error::::UserIsNotInitiator); - ensure!( - !crowdfund.is_converted, - Error::::CrowdFundAlreadyConverted - ); ensure!( !crowdfund.approved_for_funding, Error::::CrowdFundAlreadyApproved @@ -259,16 +272,15 @@ pub mod pallet { let who = ensure_signed(origin)?; Self::ensure_initiator(who, crowdfund_key)?; let crowdfund_whitelist_spots = WhitelistSpots::::get(crowdfund_key).unwrap_or( - BTreeMap::new() - .try_into() - .expect("Empty BTree is always smaller than bound; qed"), + BoundedBTreeMap::new() ); let mut unbounded = crowdfund_whitelist_spots.into_inner(); unbounded.extend(new_whitelist_spots); let bounded: BoundedWhitelistSpots = - unbounded.try_into().map_err(|_| Error::::Overflow)?; + unbounded.try_into().map_err(|_| Error::::WhiteListSpotLimitReached)?; + >::insert(crowdfund_key, bounded); let now = >::block_number(); Self::deposit_event(Event::WhitelistAdded(crowdfund_key, now)); @@ -385,6 +397,11 @@ pub mod pallet { let crowdfund_key = CrowdFundCount::::get(); // Todo: Take storage deposit> + let deposit_id = ::DepositHandler::take_deposit( + who.clone(), + ::CrowdFundStorageItem::get(), + CurrencyId::Native, + )?; // For now we keep them as proposed milestones until the project is able to submit. let crowdfund = CrowdFund { @@ -400,7 +417,7 @@ pub mod pallet { created_on: >::block_number(), approved_for_funding: false, cancelled: false, - is_converted: false, + deposit_id }; // Add crowdfund to list @@ -459,7 +476,7 @@ pub mod pallet { .saturating_add(::RoundExpiry::get()); RoundsExpiring::::try_mutate(expiry_block, |list| -> DispatchResult { list.try_push(crowdfund_key) - .map_err(|_| Error::::Overflow)?; + .map_err(|_| Error::::TooManyRoundsInBlock)?; Ok(()) })?; CrowdFundsInRound::::insert( @@ -552,19 +569,16 @@ pub mod pallet { crowdfund.initiator, crowdfund.milestones.into_inner(), FundingType::Proposal, - ) - .map_err(|_| Error::::CrowdFundConversionFailedGeneric)?; + )?; + + ::DepositHandler::return_deposit(crowdfund.deposit_id)?; + CrowdFunds::::remove(crowdfund_key); - CrowdFunds::::mutate(crowdfund_key, |crowdfund| { - if let Some(cf) = crowdfund { - cf.is_converted = true - } - Ok::<(), DispatchError>(()) - })?; Self::deposit_event(Event::CrowdFundApproved(crowdfund_key)); Ok(().into()) } + /// Actually calls storage. Could be improved. pub fn ensure_initiator( who: T::AccountId, crowdfund_key: CrowdFundKey, @@ -577,6 +591,7 @@ pub mod pallet { } } + /// Ensure the identity of an account is either Reasonable or KnownGood. fn ensure_identity_is_decent(who: &T::AccountId) -> Result<(), Error> { let identity = pallet_identity::Pallet::::identity(who).ok_or(Error::::IdentityNeeded)?; @@ -605,10 +620,8 @@ pub mod pallet { pub agreement_hash: H256, pub initiator: AccountIdOf, pub created_on: BlockNumberFor, - pub is_converted: bool, + pub deposit_id: DepositIdOf, } - - // Called to ensure that an account is is a contributor to a crowdfund. } // Warning: This will allow the withdrawal of funds, approve is a governance action so should not be a problem. diff --git a/pallets/crowdfunding/src/mock.rs b/pallets/crowdfunding/src/mock.rs index 410180bc..ba7221e3 100644 --- a/pallets/crowdfunding/src/mock.rs +++ b/pallets/crowdfunding/src/mock.rs @@ -67,11 +67,12 @@ impl frame_system::Config for Test { parameter_types! { pub RoundExpiry: BlockNumber = 100; pub MaxKeysPerRound: u32 = 50; - pub MaxContributionsPerCrowdFund: u32 = 1000; + pub MaxContributionsPerCrowdFund: u32 = 127; pub MaxMilestonesPerCrowdFund: u32 = 50; pub MaxWhitelistPerCrowdFund: u32 = 50; pub MinimumRequiredFunds: Balance = 2000; pub MinimumContribution: Balance = 5; + pub CrowdFundStorageItem: StorageItem = StorageItem::CrowdFund; } impl pallet_crowdfunding::Config for Test { @@ -85,6 +86,8 @@ impl pallet_crowdfunding::Config for Test { type IsIdentityRequired = IsIdentityRequired; type AuthorityOrigin = EnsureRoot; type IntoProposals = pallet_proposals::Pallet; + type CrowdFundStorageItem = CrowdFundStorageItem; + type DepositHandler = MockDepositHandler; type WeightInfo = (); } @@ -235,7 +238,7 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { - let initial_balance = 10_000_000u64; + let initial_balance = 100_000_000_000_000u64; System::set_block_number(1); let _ = Tokens::deposit(CurrencyId::Native, &ALICE, initial_balance); let _ = Tokens::deposit(CurrencyId::Native, &BOB, initial_balance); diff --git a/pallets/crowdfunding/src/tests.rs b/pallets/crowdfunding/src/tests.rs index 8a5828a2..bb90b948 100644 --- a/pallets/crowdfunding/src/tests.rs +++ b/pallets/crowdfunding/src/tests.rs @@ -5,11 +5,12 @@ use crate::{ }; use common_types::CurrencyId; use frame_support::{assert_noop, assert_ok, traits::Hooks}; -use orml_traits::MultiReservableCurrency; +use orml_traits::{MultiReservableCurrency, MultiCurrency}; use pallet_proposals::ProposedMilestone; use sp_arithmetic::per_things::Percent; use sp_core::H256; use sp_runtime::DispatchError::BadOrigin; +use sp_core::sr25519::{Public}; use test_utils::*; pub(crate) mod test_utils { @@ -148,7 +149,7 @@ fn update_crowdfund_already_converted() { None, None, ), - Error::::CrowdFundAlreadyConverted + Error::::CrowdFundDoesNotExist ); }); } @@ -455,3 +456,37 @@ fn on_initialize_removes_contribution_round() { assert!(!RoundsExpiring::::contains_key(expiry_block)); }); } + +#[test] +fn contribute_too_many_contributions() { + new_test_ext().execute_with(|| { + let key = create_cf_default(*ALICE, 1_000_000u64); + let max_contributions = ::MaxContributionsPerCrowdFund::get(); + let _ = + CrowdFunding::open_contributions(RuntimeOrigin::root(), key).expect("should be fine."); + (0..max_contributions + 10).for_each(move |i| { + let acc = Public::from_raw([i as u8; 32]); + let _ = ::MultiCurrency::deposit(CurrencyId::Native, &acc, 100_000); + if i < max_contributions { + assert_ok!(CrowdFunding::contribute(RuntimeOrigin::signed(acc), key, 10_000)); + } else { + assert_noop!(CrowdFunding::contribute(RuntimeOrigin::signed(acc), key, 10_000), Error::::TooManyContributions); + } + }); + }); +} + +#[test] +fn too_many_rounds_in_the_block() { + new_test_ext().execute_with(|| { + let max = ::MaxKeysPerRound::get(); + (0..max + 10).for_each(move |i| { + let key = create_cf_default(*ALICE, 1_000_000u64); + if i < max { + assert_ok!(CrowdFunding::open_contributions(RuntimeOrigin::root(), key)); + } else { + assert_noop!(CrowdFunding::open_contributions(RuntimeOrigin::root(), key), Error::::TooManyRoundsInBlock); + } + }); + }); +} diff --git a/pallets/deposits/src/benchmarking.rs b/pallets/deposits/src/benchmarking.rs index 7fc5aa56..04eec0ad 100644 --- a/pallets/deposits/src/benchmarking.rs +++ b/pallets/deposits/src/benchmarking.rs @@ -1,3 +1,2 @@ #[allow(unused)] -//use crate::Pallet as Template; use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; diff --git a/pallets/proposals/Cargo.toml b/pallets/proposals/Cargo.toml index 2ac43262..f4e0a29e 100644 --- a/pallets/proposals/Cargo.toml +++ b/pallets/proposals/Cargo.toml @@ -62,7 +62,7 @@ common-runtime = { path = "../../runtime/common"} [features] default = ['std'] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks"] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "common-runtime/runtime-benchmarks"] std = [ "codec/std", "serde/std", diff --git a/runtime/imbue-kusama/Cargo.toml b/runtime/imbue-kusama/Cargo.toml index f0c9ee84..45e6a326 100644 --- a/runtime/imbue-kusama/Cargo.toml +++ b/runtime/imbue-kusama/Cargo.toml @@ -103,6 +103,7 @@ pallet-proposals = { path = '../../pallets/proposals', default-features = false pallet-briefs = {path = '../../pallets/briefs', default-features = false } pallet-grants = {path = '../../pallets/grants', default-features = false } pallet-deposits = {path = '../../pallets/deposits', default-features = false } +pallet-crowdfunding = {path = '../../pallets/crowdfunding', default-features = false } common-traits = { path = "../../libs/common-traits", default-features = false } common-types = { path = "../../libs/common-types", default-features = false } @@ -178,6 +179,7 @@ std = [ 'pallet-proposals/std', 'pallet-briefs/std', 'pallet-grants/std', + 'pallet-crowdfunding/std', ] runtime-benchmarks = [ @@ -197,6 +199,7 @@ runtime-benchmarks = [ 'pallet-proposals/runtime-benchmarks', 'pallet-briefs/runtime-benchmarks', 'pallet-grants/runtime-benchmarks', + 'pallet-crowdfunding/runtime-benchmarks', ] # A feature that should be enabled when the runtime should be build for on-chain diff --git a/runtime/imbue-kusama/src/lib.rs b/runtime/imbue-kusama/src/lib.rs index 63c21696..011415e6 100644 --- a/runtime/imbue-kusama/src/lib.rs +++ b/runtime/imbue-kusama/src/lib.rs @@ -761,7 +761,6 @@ parameter_types! { pub const PercentRequiredForVoteToPass: Percent = Percent::from_percent(75u8); pub const MaximumContributorsPerProject: u32 = 5000; pub const RefundsPerBlock: u8 = 20; - pub const IsIdentityRequired: bool = false; pub const MilestoneVotingWindow: BlockNumber = 100800; pub const ImbueFee: Percent = Percent::from_percent(5_u8); pub const ExpiringProjectRoundsPerBlock: u32 = 50; @@ -830,6 +829,7 @@ impl DepositCalculator for ImbueDepositCalculator { u: Self::StorageItem, currency: CurrencyId, ) -> Result { + // A safe guard as Imbue only takes deposits in the $IMBU if currency != CurrencyId::Native { return Err(pallet_deposits::pallet::Error::::UnsupportedCurrencyType.into()); } @@ -841,6 +841,7 @@ impl DepositCalculator for ImbueDepositCalculator { }) } } + impl pallet_deposits::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MultiCurrency = Currencies; @@ -850,6 +851,34 @@ impl pallet_deposits::Config for Runtime { type DepositSlashAccount = TreasuryAccount; } +parameter_types! { + // SAFETY: This is iterated in the hooks of linear complexity (O(n) + 1)r/w. + pub MaxKeysPerRound: u32 = 100; + // (?) + pub MaxContributionsPerCrowdFund: u32 = 300; + // (?) + pub MaxWhitelistPerCrowdFund: u32 = 300; + pub IsIdentityRequired: bool = false; + pub TwoWeeks: BlockNumber = DAYS * 14; + pub CrowdFundStorageItem: StorageDepositItems = StorageDepositItems::CrowdFund; +} + +impl pallet_crowdfunding::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MultiCurrency = Currencies; + type RoundExpiry = TwoWeeks; + type MaxKeysPerRound = MaxKeysPerRound; + type MaxMilestonesPerCrowdFund = MaxMilestonesPerProject; + type MaxWhitelistPerCrowdFund = MaxWhitelistPerCrowdFund; + type MaxContributionsPerCrowdFund = MaxContributionsPerCrowdFund; + type IsIdentityRequired = IsIdentityRequired; + type AuthorityOrigin = EnsureRoot; + type IntoProposals = pallet_proposals::Pallet; + type DepositHandler = Deposits; + type CrowdFundStorageItem = CrowdFundStorageItem; + type WeightInfo = pallet_crowdfunding::weights::SubstrateWeight; +} + construct_runtime! { pub enum Runtime where Block = Block, @@ -907,6 +936,7 @@ construct_runtime! { ImbueBriefs: pallet_briefs::{Pallet, Call, Storage, Event} = 101, ImbueGrants: pallet_grants::{Pallet, Call, Storage, Event} = 102, Deposits: pallet_deposits::{Pallet, Storage, Event} = 103, + ImbueCrowdfunding: pallet_crowdfunding::{Pallet, Call, Storage, Event} = 104, } } @@ -952,6 +982,7 @@ mod benches { [pallet_proposals, ImbueProposals] [pallet_briefs, ImbueBriefs] [pallet_grants, ImbueGrants] + [pallet_crowdfunding, ImbueCrowdfunding] ); }