diff --git a/pallets/communities-manager/src/benchmarking.rs b/pallets/communities-manager/src/benchmarking.rs index ea95b488..6ceeb942 100644 --- a/pallets/communities-manager/src/benchmarking.rs +++ b/pallets/communities-manager/src/benchmarking.rs @@ -1,14 +1,11 @@ //! Benchmarking setup for pallet-communities -#![cfg(feature = "runtime-benchmarks")] use super::*; use frame_benchmarking::v2::*; - -use self::Pallet as CommunitiesManager; +use Pallet as CommunitiesManager; use frame_system::RawOrigin; -use pallet_referenda::Curve; -use sp_runtime::{str_array as s, traits::StaticLookup, Perbill}; +use sp_runtime::traits::StaticLookup; type RuntimeEventFor = ::RuntimeEvent; @@ -37,39 +34,14 @@ mod benchmarks { _( RawOrigin::Root, community_id, - TrackInfo { - name: s("Test Track"), - max_deciding: 1, - decision_deposit: 0u32.into(), - prepare_period: 1u32.into(), - decision_period: 2u32.into(), - confirm_period: 1u32.into(), - min_enactment_period: 1u32.into(), - min_approval: pallet_referenda::Curve::LinearDecreasing { - length: Perbill::one(), - floor: Perbill::zero(), - ceil: Perbill::one(), - }, - min_support: Curve::LinearDecreasing { - length: Perbill::one(), - floor: Perbill::zero(), - ceil: Perbill::one(), - }, - }, + BoundedVec::truncate_from(b"Test Community".into()), Some(admin_origin_caller.clone()), None, Some(T::Lookup::unlookup(first_member)), ); // verification code - assert_has_event::( - pallet_communities::Event::::CommunityCreated { - id: community_id, - origin: admin_origin_caller, - } - .into(), - ); - assert_has_event::(crate::Event::::CommunityRegistered { id: community_id }.into()); + assert_has_event::(Event::::CommunityRegistered { id: community_id }.into()); } impl_benchmark_test_suite!( diff --git a/pallets/communities-manager/src/lib.rs b/pallets/communities-manager/src/lib.rs index 4d25218f..0da41073 100644 --- a/pallets/communities-manager/src/lib.rs +++ b/pallets/communities-manager/src/lib.rs @@ -26,15 +26,19 @@ use pallet_communities::{ }, Origin as CommunityOrigin, }; -use pallet_nfts::{CollectionConfig, MintSettings, MintType::Issuer}; +use pallet_nfts::CollectionConfig; use pallet_referenda::{TrackInfo, TracksInfo}; type TrackInfoOf = TrackInfo, BlockNumberFor>; #[frame_support::pallet] pub mod pallet { + use sp_runtime::str_array; + use super::*; + type CommunityName = BoundedVec>; + /// Configure the pallet by specifying the parameters and types on which it /// depends. #[pallet::config] @@ -82,6 +86,8 @@ pub mod pallet { // Errors inform users that something worked or went wrong. #[pallet::error] pub enum Error { + /// Community name didn't contain valid utf8 characters + InvalidCommunityName, /// It was not possible to register the community CannotRegister, } @@ -96,16 +102,18 @@ pub mod pallet { pub fn register( origin: OriginFor, community_id: CommunityIdOf, - track_info: TrackInfoOf, + name: CommunityName, maybe_admin_origin: Option>, maybe_decision_method: Option>, _maybe_first_member: Option>, ) -> DispatchResult { let maybe_deposit = T::CreateOrigin::ensure_origin(origin)?; - // This implies depositing (Deposit (Hold | -> Treasury)) + let community_name = core::str::from_utf8(&name).map_err(|_| Error::::InvalidCommunityName)?; let community_origin: RuntimeOriginFor = CommunityOrigin::::new(community_id).into(); let admin_origin = maybe_admin_origin.unwrap_or(community_origin.clone().into_caller()); + // Register first to check if community exists + pallet_communities::Pallet::::register(&admin_origin, &community_id, maybe_deposit)?; if let Some(decision_method) = maybe_decision_method { pallet_communities::Pallet::::set_decision_method( @@ -115,8 +123,6 @@ pub mod pallet { )?; } - pallet_communities::Pallet::::register(&admin_origin, &community_id, maybe_deposit)?; - let community_account = pallet_communities::Pallet::::community_account(&community_id); // Create memberships collection for community @@ -127,26 +133,46 @@ pub mod pallet { &CollectionConfig { settings: Default::default(), max_supply: None, - mint_settings: MintSettings { - mint_type: Issuer, - price: None, - start_block: None, - end_block: None, - default_item_settings: Default::default(), - }, + mint_settings: Default::default(), }, )?; // Create governance track for community - T::Tracks::insert(community_id, track_info, community_origin.into_caller())?; - + T::Tracks::insert( + community_id, + Self::default_tack(community_name), + community_origin.into_caller(), + )?; // Induct community at Kreivo Governance with rank 1 T::RankedCollective::induct(&community_account)?; - T::RankedCollective::promote(&community_account)?; Self::deposit_event(Event::::CommunityRegistered { id: community_id }); - Ok(()) } } + + impl Pallet { + fn default_tack(name: &str) -> TrackInfoOf { + use sp_runtime::Perbill; + TrackInfo { + name: str_array(name), + max_deciding: 1, + decision_deposit: 0u8.into(), + prepare_period: 1u8.into(), + decision_period: u8::MAX.into(), + confirm_period: 1u8.into(), + min_enactment_period: 1u8.into(), + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(0), + ceil: Perbill::from_percent(50), + }, + } + } + } } diff --git a/pallets/communities/src/functions.rs b/pallets/communities/src/functions.rs index 56115c0b..d4d702fc 100644 --- a/pallets/communities/src/functions.rs +++ b/pallets/communities/src/functions.rs @@ -45,11 +45,19 @@ impl Pallet { Info::::mutate(community_id, |c| c.as_mut().map(|c| c.state = state)); } + /// Stores an initial info about the community + /// Sets the caller as the community admin, the initial community state + /// to its default value(awaiting) pub fn register( admin: &PalletsOriginOf, community_id: &CommunityIdOf, maybe_deposit: Option<(NativeBalanceOf, AccountIdOf, AccountIdOf)>, ) -> DispatchResult { + ensure!( + !Self::community_exists(community_id), + Error::::CommunityAlreadyExists + ); + if let Some((deposit, depositor, depositee)) = maybe_deposit { T::Balances::transfer( &depositor, @@ -59,27 +67,10 @@ impl Pallet { )?; } - Self::do_register_community(admin, community_id) - } - - /// Stores an initial info about the community - /// Sets the caller as the community admin, the initial community state - /// to its default value(awaiting) - pub(crate) fn do_register_community(admin: &PalletsOriginOf, community_id: &T::CommunityId) -> DispatchResult { - ensure!( - !Self::community_exists(community_id), - Error::::CommunityAlreadyExists - ); - CommunityIdFor::::insert(admin, community_id); Info::::insert(community_id, CommunityInfo::default()); frame_system::Pallet::::inc_providers(&Self::community_account(community_id)); - Self::deposit_event(crate::Event::CommunityCreated { - id: *community_id, - origin: admin.clone(), - }); - Ok(()) } diff --git a/pallets/communities/src/lib.rs b/pallets/communities/src/lib.rs index 0498f4a2..c1e691c8 100644 --- a/pallets/communities/src/lib.rs +++ b/pallets/communities/src/lib.rs @@ -362,6 +362,11 @@ pub mod pallet { let maybe_deposit = T::CreateOrigin::ensure_origin(origin)?; Self::register(&admin_origin, &community_id, maybe_deposit)?; + + Self::deposit_event(crate::Event::CommunityCreated { + id: community_id, + origin: admin_origin, + }); Ok(()) } @@ -560,9 +565,8 @@ pub mod pallet { let max_members = u16::MAX as u32; if let Some((i, _)) = CommunityVotes::::iter_keys().find(|(i, _)| T::Polls::as_ongoing(*i).is_none()) { - match CommunityVotes::::clear_prefix(i, max_members, None) { - _ => Weight::zero(), - } + let _ = CommunityVotes::::clear_prefix(i, max_members, None); + Weight::zero() } else { Weight::zero() } diff --git a/pallets/communities/src/mock.rs b/pallets/communities/src/mock.rs index 4722f3cd..92c90815 100644 --- a/pallets/communities/src/mock.rs +++ b/pallets/communities/src/mock.rs @@ -3,9 +3,12 @@ use frame_support::{ parameter_types, traits::{ fungible::HoldConsideration, tokens::nonfungible_v2::ItemOf, AsEnsureOriginWithArg, ConstU128, ConstU16, - ConstU32, ConstU64, EitherOf, EnsureOriginWithArg, EqualPrivilegeOnly, Footprint, OriginTrait, + ConstU32, ConstU64, EitherOf, EnsureOriginWithArg, EqualPrivilegeOnly, Footprint, + }, + weights::{ + constants::{WEIGHT_REF_TIME_PER_NANOS, WEIGHT_REF_TIME_PER_SECOND}, + Weight, }, - weights::{constants::WEIGHT_REF_TIME_PER_NANOS, constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, PalletId, }; use frame_system::{EnsureRoot, EnsureRootWithSuccess, EnsureSigned}; @@ -21,7 +24,7 @@ pub use virto_common::{CommunityId, MembershipId}; use crate::{ self as pallet_communities, - origin::{DecisionMethod, EnsureCommunity, EnsureCreateOrigin}, + origin::{DecisionMethod, EnsureCommunity, EnsureSignedPays}, types::{Tally, VoteWeight}, }; @@ -406,6 +409,12 @@ impl BenchmarkHelper for CommunityBenchmarkHelper { } } +parameter_types! { + pub const NoPay: Option<(Balance, AccountId, AccountId)> = None; +} +type RootCreatesCommunitiesForFree = EnsureRootWithSuccess; +type AnyoneElsePays = EnsureSignedPays, RootAccount>; + impl pallet_communities::Config for Test { type PalletId = CommunitiesPalletId; type CommunityId = CommunityId; @@ -416,8 +425,7 @@ impl pallet_communities::Config for Test { type MemberMgmt = Nfts; type Polls = Referenda; - type CreateOrigin = - EnsureCreateOrigin, EnsureSigned, RootAccount, ConstU128<10>>; + type CreateOrigin = EitherOf; type AdminOrigin = EnsureCommunity; type MemberMgmtOrigin = EnsureCommunity; @@ -544,7 +552,7 @@ impl TestEnvBuilder { .expect("should include decision_method on add_community"); let community_origin: RuntimeOrigin = Self::create_community_origin(community_id); - Communities::create(RuntimeOrigin::root(), community_origin.caller().clone(), *community_id) + Communities::create(RuntimeOrigin::root(), community_origin.caller.clone(), *community_id) .expect("can add community"); Communities::set_decision_method(community_origin.clone(), *community_id, decision_method.clone()) @@ -575,7 +583,7 @@ impl TestEnvBuilder { RuntimeOrigin::root(), *community_id, track_info.clone(), - community_origin.caller().clone(), + community_origin.caller.clone(), ) .expect("can add track"); } diff --git a/pallets/communities/src/origin.rs b/pallets/communities/src/origin.rs index f1024109..adf2b0b5 100644 --- a/pallets/communities/src/origin.rs +++ b/pallets/communities/src/origin.rs @@ -1,16 +1,17 @@ use crate::{ types::{CommunityIdOf, CommunityState::Active, MembershipIdOf, RuntimeOriginFor}, - AccountIdOf, CommunityIdFor, Config, Info, NativeBalanceOf, Pallet, + AccountIdOf, CommunityIdFor, Config, Info, Pallet, }; use core::marker::PhantomData; use fc_traits_memberships::Inspect; use frame_support::{ pallet_prelude::*, - traits::{membership::GenericRank, EnsureOriginWithArg, OriginTrait}, + traits::{membership::GenericRank, EnsureOriginWithArg, MapSuccess, OriginTrait}, }; +use frame_system::EnsureSigned; #[cfg(feature = "xcm")] use sp_runtime::traits::TryConvert; -use sp_runtime::Permill; +use sp_runtime::{morph_types, Permill}; pub struct EnsureCommunity(PhantomData); @@ -45,36 +46,19 @@ where } } -pub struct EnsureCreateOrigin(PhantomData<(T, R, P, D, A)>); - -impl EnsureOrigin - for EnsureCreateOrigin -where - OuterOrigin: From> + Clone, - T: Config, - Root: EnsureOrigin, - Permissionless: EnsureOrigin>, - Destination: Get>, - Amount: Get>, -{ - type Success = Option<(NativeBalanceOf, AccountIdOf, AccountIdOf)>; - - fn try_origin(o: OuterOrigin) -> Result { - match Root::try_origin(o.clone()) { - Ok(_) => Ok(None), - _ => match Permissionless::try_origin(o.clone()) { - Ok(sender) => Ok(Some((Amount::get(), sender, Destination::get()))), - _ => Err(o), - }, - } - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(frame_system::Origin::::Root.into()) - } +morph_types! { + pub type PaymentForCreate< + AccountId, + GetAmount: TypedGet, + GetReceiver: TypedGet + >: Morph = |sender: AccountId| -> Option<(GetAmount::Type, AccountId, GetReceiver::Type)> { + Some((GetAmount::get(), sender, GetReceiver::get())) + }; } +pub type EnsureSignedPays = + MapSuccess>, PaymentForCreate, Amount, Beneficiary>>; + pub struct EnsureMember(PhantomData); impl EnsureOriginWithArg, CommunityIdOf> for EnsureMember diff --git a/runtime/kreivo/src/communities/governance.rs b/runtime/kreivo/src/communities/governance.rs index 745203c4..8a9a128a 100644 --- a/runtime/kreivo/src/communities/governance.rs +++ b/runtime/kreivo/src/communities/governance.rs @@ -1,6 +1,7 @@ use super::*; use frame_system::{pallet_prelude::BlockNumberFor, EnsureRootWithSuccess}; +use pallet_communities::RuntimeOriginFor; use sp_std::marker::PhantomData; use pallet_referenda::{BalanceOf, PalletsOriginOf, TrackIdOf, TracksInfo}; diff --git a/runtime/kreivo/src/communities/mod.rs b/runtime/kreivo/src/communities/mod.rs index 3757bbe9..820eb306 100644 --- a/runtime/kreivo/src/communities/mod.rs +++ b/runtime/kreivo/src/communities/mod.rs @@ -1,15 +1,9 @@ use super::*; -use frame_support::{ - pallet_prelude::{EnsureOrigin, PhantomData}, - traits::OriginTrait, -}; -use frame_system::EnsureSigned; -use pallet_communities::{ - origin::{EnsureCommunity, EnsureCreateOrigin}, - types::RuntimeOriginFor, -}; -use sp_runtime::traits::AccountIdConversion; +use frame_support::traits::TryMapSuccess; +use frame_system::{EnsureRootWithSuccess, EnsureSigned}; +use pallet_communities::origin::{EnsureCommunity, EnsureSignedPays}; +use sp_runtime::{morph_types, traits::AccountIdConversion}; use virto_common::{CommunityId, MembershipId}; pub mod governance; @@ -38,49 +32,28 @@ use ::{ }; parameter_types! { - pub const CommunityPalletId: PalletId = PalletId(*b"kv/cmtys"); + pub const CommunityPalletId: PalletId = PalletId(*b"kv/cmtys"); pub const MembershipsCollectionId: CommunityId = 0; pub const MembershipNftAttr: &'static [u8; 10] = b"membership"; - pub const CommunityDepositAmount: Balance = UNITS; + pub const CommunityDepositAmount: Balance = UNITS / 2; + pub const NoPay: Option<(Balance, AccountId, AccountId)> = None; } -pub struct EnsureCommunityAccountId(PhantomData); - -impl EnsureOrigin> for EnsureCommunityAccountId -where - RuntimeOriginFor: - OriginTrait + From> + From>, - T: pallet_communities::Config, -{ - type Success = T::CommunityId; - - fn try_origin(o: RuntimeOriginFor) -> Result> { - match o.clone().into() { - Ok(frame_system::RawOrigin::Signed(account_id)) => { - let (_, community_id) = PalletId::try_from_sub_account(&account_id).ok_or(o.clone())?; - Ok(community_id) - } - _ => Err(o), - } - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result, ()> { - Ok(Origin::new(T::BenchmarkHelper::community_id()).into()) - } +morph_types! { + pub type AccountToCommunityId: TryMorph = |a: AccountId| -> Result { + PalletId::try_from_sub_account(&a).map(|(_, id)| id).ok_or(()) + }; } +type EnsureCommunityAccount = TryMapSuccess, AccountToCommunityId>; + +type RootCreatesCommunitiesForFree = EnsureRootWithSuccess; +type AnyoneElsePays = EnsureSignedPays; impl pallet_communities::Config for Runtime { type CommunityId = CommunityId; - type CreateOrigin = EnsureCreateOrigin< - Self, - EnsureRoot, - EnsureSigned, - TreasuryAccount, - CommunityDepositAmount, - >; - type AdminOrigin = EitherOf, EnsureCommunityAccountId>; - type MemberMgmtOrigin = EitherOf, EnsureCommunityAccountId>; + type CreateOrigin = EitherOf; + type AdminOrigin = EitherOf, EnsureCommunityAccount>; + type MemberMgmtOrigin = EitherOf, EnsureCommunityAccount>; type MemberMgmt = CommunityMemberships; type MembershipId = MembershipId;