diff --git a/pallets/communities/src/functions.rs b/pallets/communities/src/functions.rs index 08aa8355..7b99c726 100644 --- a/pallets/communities/src/functions.rs +++ b/pallets/communities/src/functions.rs @@ -1,4 +1,16 @@ +// <<<<<<< Updated upstream +use self::types::BoundedCallOf; use super::{origin::DecisionMethod, *}; +// ======= +// use crate::{ +// origin::DecisionMethod, +// types::{ +// AccountIdOf, BoundedCallOf, CommunityIdOf, CommunityInfo, CommunityState, ConstSizedField, MembershipIdOf, +// PalletsOriginOf, PollIndexOf, RuntimeCallFor, Tally, Vote, VoteOf, VoteWeight, +// }, +// CommunityDecisionMethod, CommunityIdFor, CommunityVotes, Config, Error, HoldReason, Info, Metadata, Pallet, +// }; +// >>>>>>> Stashed changes use fc_traits_memberships::{GenericRank, Inspect, Rank}; use frame_support::{ dispatch::PostDispatchInfo, @@ -8,14 +20,14 @@ use frame_support::{ fungible::{Mutate, MutateFreeze}, fungibles::{InspectHold, MutateHold}, tokens::Precision, - Polling, + Polling, QueryPreimage, }, }; use sp_runtime::{ traits::{AccountIdConversion, Dispatchable}, DispatchResultWithInfo, TokenError, }; -use sp_std::{vec, vec::Vec}; +use sp_std::vec::Vec; impl Pallet { #[inline] @@ -196,13 +208,14 @@ impl Pallet { Ok(()) } - pub(crate) fn do_dispatch_as_community_account( + pub(crate) fn do_dispatch_as( community_id: &CommunityIdOf, - call: RuntimeCallFor, + call: BoundedCallOf, ) -> DispatchResultWithInfo { let community_account = Self::community_account(community_id); let signer = frame_system::RawOrigin::Signed(community_account); + let (call, _) = T::Preimages::realize(&call)?; let post = call.dispatch(signer.into()).map_err(|e| e.error)?; Ok(post) } diff --git a/pallets/communities/src/lib.rs b/pallets/communities/src/lib.rs index 9524f2ee..43feceee 100644 --- a/pallets/communities/src/lib.rs +++ b/pallets/communities/src/lib.rs @@ -142,12 +142,11 @@ pub mod pallet { use frame_support::{ dispatch::{DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::*, - traits::{fungible, fungibles, EnsureOrigin, IsSubType, OriginTrait, Polling}, + traits::{fungible, fungibles, EnsureOrigin, IsSubType, OriginTrait, Polling, QueryPreimage}, Blake2_128Concat, Parameter, }; use frame_system::pallet_prelude::{ensure_signed, BlockNumberFor, OriginFor}; use sp_runtime::traits::{Dispatchable, StaticLookup}; - use sp_std::prelude::Box; const ONE: NonZeroU8 = NonZeroU8::MIN; @@ -181,6 +180,9 @@ pub mod pallet { /// Origin authorized to manage memeberships of an active community type MemberMgmtOrigin: EnsureOrigin, Success = Self::CommunityId>; + /// Origin authorized to dispatch calls as an account or origin of a community + type DispatchOrigin: EnsureOrigin, Success = Self::CommunityId>; + type Polls: Polling< Tally, Class = CommunityIdOf, @@ -200,6 +202,9 @@ pub mod pallet { + fungible::freeze::Inspect + fungible::freeze::Mutate; + /// Fetch calls that a Community can dispatch with its account + type Preimages: QueryPreimage; + /// The overarching call type. type RuntimeCall: Parameter + Dispatchable, PostInfo = PostDispatchInfo> @@ -236,7 +241,7 @@ pub mod pallet { /// The origin of the pallet #[pallet::origin] - pub type Origin = origin::RawOrigin; + pub type Origin = origin::RawOrigin, MembershipIdOf>; /// A reason for the pallet communities placing a hold on funds. #[pallet::composite_enum] @@ -526,33 +531,13 @@ pub mod pallet { /// Dispatch a callable as the community account #[pallet::call_index(11)] - #[pallet::weight({ - let di = call.get_dispatch_info(); - let weight = T::WeightInfo::dispatch_as_account() - .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(di.weight); - (weight, di.class) - })] - pub fn dispatch_as_account(origin: OriginFor, call: Box>) -> DispatchResultWithPostInfo { - let community_id = T::MemberMgmtOrigin::ensure_origin(origin)?; - Self::do_dispatch_as_community_account(&community_id, *call) + pub fn dispatch_as( + origin: OriginFor, + target: DispatchTarget, MembershipIdOf>, + call: BoundedCallOf, + ) -> DispatchResultWithPostInfo { + let community_id = T::DispatchOrigin::ensure_origin(origin)?; + Self::do_dispatch_as(&community_id, call) } - - // /// Dispatch a callable as the community account - // #[pallet::call_index(12)] - // #[pallet::weight({ - // let di = call.get_dispatch_info(); - // let weight = T::WeightInfo::dispatch_as_account() - // .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - // .saturating_add(di.weight); - // (weight, di.class) - // })] - // // #[cfg(any(test, feature = "testnet"))] - // pub fn dispatch_as_origin(origin: OriginFor, call: Box>) - // -> DispatchResultWithPostInfo { let community_id = - // T::MemberMgmtOrigin::ensure_origin(origin)?; let origin = - // crate::Origin::::new(community_id); let post = - // call.dispatch(origin.into()).map_err(|e| e.error)?; Ok(post) - // } } } diff --git a/pallets/communities/src/mock.rs b/pallets/communities/src/mock.rs index 92c90815..138c1103 100644 --- a/pallets/communities/src/mock.rs +++ b/pallets/communities/src/mock.rs @@ -424,10 +424,12 @@ impl pallet_communities::Config for Test { type Balances = Balances; type MemberMgmt = Nfts; type Polls = Referenda; + type Preimages = Preimage; type CreateOrigin = EitherOf; type AdminOrigin = EnsureCommunity; type MemberMgmtOrigin = EnsureCommunity; + type DispatchOrigin = EnsureCommunity; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; diff --git a/pallets/communities/src/origin.rs b/pallets/communities/src/origin.rs index adf2b0b5..3651fc37 100644 --- a/pallets/communities/src/origin.rs +++ b/pallets/communities/src/origin.rs @@ -17,7 +17,9 @@ pub struct EnsureCommunity(PhantomData); impl EnsureOrigin> for EnsureCommunity where - RuntimeOriginFor: OriginTrait + Into, RuntimeOriginFor>> + From>, + RuntimeOriginFor: OriginTrait + + Into, MembershipIdOf>, RuntimeOriginFor>> + + From, MembershipIdOf>>, T: Config, { type Success = T::CommunityId; @@ -95,32 +97,33 @@ where /// Origin to represent the voice of a community or a subset of its members /// as well as the voting preference of said group. #[derive(TypeInfo, Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, Debug)] -pub struct RawOrigin { - community_id: CommunityIdOf, - subset: Option>, +pub struct RawOrigin { + community_id: CommunityId, + subset: Option>, } -impl RawOrigin { - pub const fn new(community_id: CommunityIdOf) -> Self { +impl RawOrigin { + pub const fn new(community_id: CommunityId) -> Self { RawOrigin { community_id, subset: None, } } - pub fn with_subset(&mut self, s: Subset) { + pub fn with_subset(&mut self, s: Subset) { self.subset = Some(s); } - pub fn id(&self) -> CommunityIdOf { - self.community_id + pub fn id(&self) -> CommunityId { + self.community_id.clone() } } /// Subsets of the community can also have a voice #[derive(Clone, Debug, Decode, Encode, Eq, MaxEncodedLen, PartialEq, TypeInfo)] -pub enum Subset { - Member(MembershipIdOf), +pub enum Subset { + Named([u8; 4]), + Member(MembershipId), Members { count: u32 }, Fraction(Permill), AtLeastRank(GenericRank), @@ -137,13 +140,13 @@ pub enum DecisionMethod { } #[cfg(feature = "xcm")] -impl TryConvert, xcm::v3::MultiLocation> for RawOrigin +impl TryConvert + for RawOrigin where - T: Config, - RuntimeOriginFor: Into, RuntimeOriginFor>>, - xcm::v3::Junction: TryFrom>, + RuntimeOrigin: Clone + Into, RuntimeOrigin>>, + xcm::v3::Junction: TryFrom>, { - fn try_convert(o: RuntimeOriginFor) -> Result> { + fn try_convert(o: RuntimeOrigin) -> Result { let Ok(community @ RawOrigin { .. }) = o.clone().into() else { return Err(o); }; @@ -153,14 +156,13 @@ where } #[cfg(feature = "xcm")] -impl TryFrom> for xcm::v3::Junction +impl TryFrom> for xcm::v3::Junction where - T: Config, - u32: From>, + u32: From, { type Error = (); - fn try_from(o: RawOrigin) -> Result { + fn try_from(o: RawOrigin) -> Result { use xcm::v3::{BodyId, BodyPart, Junction::Plurality}; let part = match o.subset { None => BodyPart::Voice, @@ -180,10 +182,9 @@ where } #[cfg(feature = "xcm")] -impl TryFrom for RawOrigin +impl TryFrom for RawOrigin where - T: Config, - T::CommunityId: From + From, + C: From + From + Clone, { type Error = (); @@ -212,10 +213,10 @@ impl EnsureOrigin for AsSignedByCommunity where OuterOrigin: OriginTrait + From> - + From> + + From, MembershipIdOf>> + Clone + Into, OuterOrigin>> - + Into, OuterOrigin>>, + + Into, MembershipIdOf>, OuterOrigin>>, T: Config, { type Success = T::AccountId; diff --git a/pallets/communities/src/tests/weights.rs b/pallets/communities/src/tests/weights.rs index 1c9652a0..3c191fcb 100644 --- a/pallets/communities/src/tests/weights.rs +++ b/pallets/communities/src/tests/weights.rs @@ -30,7 +30,7 @@ fn weights() { ("vote", SubstrateWeight::::vote()), ("remove_vote", SubstrateWeight::::remove_vote()), ("unlock", SubstrateWeight::::unlock()), - ("dispatch_as_account", SubstrateWeight::::dispatch_as_account()), + ("dispatch_as", SubstrateWeight::::dispatch_as()), ] { println!("{function}: {weight:?}",); println!( diff --git a/pallets/communities/src/types.rs b/pallets/communities/src/types.rs index 14a7f1aa..620607e9 100644 --- a/pallets/communities/src/types.rs +++ b/pallets/communities/src/types.rs @@ -1,11 +1,13 @@ -use crate::origin::DecisionMethod; +use crate::origin::{DecisionMethod, RawOrigin}; use crate::{CommunityDecisionMethod, Config}; use fc_traits_memberships::{Inspect, Rank}; -use frame_support::pallet_prelude::*; -use frame_support::traits::{ - fungible::{self, Inspect as FunInspect}, - fungibles::{self, Inspect as FunsInspect}, - Polling, +use frame_support::{ + pallet_prelude::*, + traits::{ + fungible::{self, Inspect as FunInspect}, + fungibles::{self, Inspect as FunsInspect}, + Bounded, Polling, + }, }; use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto}; use sp_runtime::SaturatedConversion; @@ -24,6 +26,7 @@ pub type PalletsOriginOf = pub type MembershipIdOf = ::MembershipId; pub type RuntimeCallFor = ::RuntimeCall; pub type RuntimeOriginFor = ::RuntimeOrigin; +pub type BoundedCallOf = Bounded<::RuntimeCall, ::Hashing>; #[cfg(feature = "runtime-benchmarks")] pub type BenchmarkHelperOf = ::BenchmarkHelper; @@ -138,6 +141,13 @@ pub enum LockUpdateType { Remove, } +/// Target within the community the management origin can impersonate +#[derive(Clone, Debug, Decode, Encode, MaxEncodedLen, PartialEq, TypeInfo)] +pub enum DispatchTarget { + Account(Option), + Origin(RawOrigin), +} + #[cfg(feature = "runtime-benchmarks")] use {frame_benchmarking::BenchmarkError, frame_system::pallet_prelude::OriginFor}; diff --git a/pallets/communities/src/weights.rs b/pallets/communities/src/weights.rs index 4532efb0..db4613fd 100644 --- a/pallets/communities/src/weights.rs +++ b/pallets/communities/src/weights.rs @@ -43,7 +43,7 @@ pub trait WeightInfo { fn vote() -> Weight; fn remove_vote() -> Weight; fn unlock() -> Weight; - fn dispatch_as_account() -> Weight; + fn dispatch_as() -> Weight; } /// Weights for pallet_communities using the Substrate node and recommended hardware. @@ -254,7 +254,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Communities::Info` (r:1 w:0) /// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`) - fn dispatch_as_account() -> Weight { + fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3484` @@ -472,7 +472,7 @@ impl WeightInfo for () { } /// Storage: `Communities::Info` (r:1 w:0) /// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`) - fn dispatch_as_account() -> Weight { + fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3484` diff --git a/runtime/kreivo/src/weights/pallet_communities.rs b/runtime/kreivo/src/weights/pallet_communities.rs index c46f40c9..ebba63ab 100644 --- a/runtime/kreivo/src/weights/pallet_communities.rs +++ b/runtime/kreivo/src/weights/pallet_communities.rs @@ -253,7 +253,7 @@ impl pallet_communities::WeightInfo for WeightInfo { } /// Storage: `Communities::Info` (r:1 w:0) /// Proof: `Communities::Info` (`max_values`: None, `max_size`: Some(19), added: 2494, mode: `MaxEncodedLen`) - fn dispatch_as_account() -> Weight { + fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3484`