Skip to content

Commit 2722936

Browse files
pandres95johandroidjgutierrezreolanodgithub-actions[bot]
authored
[Communities] Permissionless Registering and Management of Communities (#364)
* feat(pallet-communities-manager): Initial commit Co-authored-by: Johan Alexis Duque Cadena <[email protected]> Co-authored-by: Juan Pablo Gutiérrez Restrepo <[email protected]> * change(pallet-communities-manager): define generic mechanism for `register` call * change(pallet-communities): remove metadata * change(pallet-communities): permissionless creation and administration of communities + set_admin_origin * change(pallet-communities): simplify benchmarking * fix(pallet-communities): export TryConvert only when xcm feature is enabled * change(pallet-communities): emit CommunityCreated event on do_register_community * change(pallet-communities-manager): implement pallet and benchmarkings * fix(pallet-communities): lint * fix(pallet-communities-manager): lint * change(kreivo-runtime): missing configuration changes * change(pallet-communities): add origin for ensuring permissionless creation * change(kreivo-runtime): charge 1KSM for permisionlessly creating a community. * fix(pallet-communities): ensure voting is stored on a membership-basis not account-basis * Simplify Ensure types and make more descriptive * Check first community exists + Provide default gov track * fix(pallet-communities): only iter over a single acconut's locks / double store votes and locks * fix(pallet-communities): lint * change(kreivo-runtime): adjust deposits * fix(pallet-communities): ensure holds on an asset are removed when no remaining votelocks on that asset * feat(kreivo-runtime): configure pallet-communities-manager * change(kreivo-runtime): bump minor * fix(kreivo-runtime): remove deposit mints in benchmarkings * fix(pallet-communities): on tests, must unlock on casted votes * [ci] calculate weights (#370) Co-authored-by: pandres95 <[email protected]> --------- Co-authored-by: Johan Alexis Duque Cadena <[email protected]> Co-authored-by: Juan Pablo Gutiérrez Restrepo <[email protected]> Co-authored-by: Daniel Olano <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent e7a0a44 commit 2722936

34 files changed

+1520
-584
lines changed

Diff for: Cargo.lock

+127-89
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@ pallet-asset-registry = { default-features = false, path = "pallets/asset-regist
5151
pallet-burner = { default-features = false, path = "pallets/burner" }
5252
pallet-payments = { default-features = false, path = "pallets/payments" }
5353
pallet-communities = { default-features = false, path = "pallets/communities" }
54+
pallet-communities-manager = { default-features = false, path = "pallets/communities-manager" }
5455

5556
virto-common = { default-features = false, path = "common" }
5657
runtime-common = { default-features = false, path = "runtime/common" }
5758
kusama-runtime-constants = { default-features = false, path = "runtime/kusama-runtime-constants" }
5859

5960
# Frame Contrib
6061
fc-traits-memberships = { git = "https://github.com/virto-network/frame-contrib", branch = "main", default-features = false }
61-
pallet-referenda-tracks = { git = "https://github.com/virto-network/frame-contrib", branch = "main", package="fc-pallet-referenda-tracks", default-features = false }
62+
fc-traits-tracks = { git = "https://github.com/virto-network/frame-contrib", branch = "feature/trait-tracks", default-features = false }
63+
pallet-referenda-tracks = { git = "https://github.com/virto-network/frame-contrib", branch = "feature/trait-tracks", package="fc-pallet-referenda-tracks", default-features = false }
6264

6365
# Substrate std
6466
try-runtime-cli = { git = "https://github.com/virto-network/polkadot-sdk", branch = "release-virto-v1.5.0" }

Diff for: node/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "virto-node"
3-
version = "0.10.2"
3+
version = "0.11.0"
44
authors = ['Virto Team <[email protected]>']
55
license = "GPL-3.0-only"
66
homepage = 'https://github.com/virto-network/virto-node'

Diff for: pallets/communities-manager/Cargo.toml

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
[package]
2+
name = "pallet-communities-manager"
3+
version = "0.1.0"
4+
authors = ["Virto Team<[email protected]>"]
5+
description = "This pallet helps with all the necesary steps to correctly setup a community."
6+
license = "MIT-0"
7+
homepage = 'https://github.com/virto-network/virto-node'
8+
repository = 'https://github.com/virto-network/virto-node'
9+
edition = "2021"
10+
11+
[package.metadata.docs.rs]
12+
targets = ["x86_64-unknown-linux-gnu"]
13+
14+
[dependencies]
15+
fc-traits-tracks = { workspace = true }
16+
17+
frame-benchmarking = { workspace = true, optional = true }
18+
frame-support = { workspace = true }
19+
frame-system = { workspace = true }
20+
21+
pallet-communities = { workspace = true }
22+
pallet-nfts = { workspace = true }
23+
pallet-referenda = { workspace = true }
24+
25+
log = { workspace = true }
26+
27+
parity-scale-codec = { workspace = true, features = ["derive"] }
28+
scale-info = { workspace = true, features = ["derive"] }
29+
30+
sp-runtime = { workspace = true }
31+
sp-std = { workspace = true }
32+
33+
[dev-dependencies]
34+
sp-core = { workspace = true }
35+
sp-io = { workspace = true }
36+
37+
pallet-assets = { workspace = true }
38+
pallet-balances = { workspace = true }
39+
pallet-ranked-collective = { workspace = true }
40+
pallet-referenda-tracks = { workspace = true }
41+
pallet-scheduler = { workspace = true }
42+
virto-common = { workspace = true, default-features = false, features = ["runtime"] }
43+
44+
[features]
45+
default = ["std", "testnet"]
46+
testnet = []
47+
std = [
48+
"fc-traits-tracks/std",
49+
"frame-benchmarking?/std",
50+
"frame-support/std",
51+
"frame-system/std",
52+
"log/std",
53+
"pallet-assets/std",
54+
"pallet-balances/std",
55+
"pallet-communities/std",
56+
"pallet-nfts/std",
57+
"pallet-ranked-collective/std",
58+
"pallet-referenda-tracks/std",
59+
"pallet-referenda/std",
60+
"pallet-scheduler/std",
61+
"parity-scale-codec/std",
62+
"scale-info/std",
63+
"sp-core/std",
64+
"sp-io/std",
65+
"sp-runtime/std",
66+
"sp-std/std",
67+
"virto-common/std",
68+
]
69+
runtime-benchmarks = [
70+
"frame-benchmarking/runtime-benchmarks",
71+
"frame-support/runtime-benchmarks",
72+
"frame-system/runtime-benchmarks",
73+
"pallet-assets/runtime-benchmarks",
74+
"pallet-balances/runtime-benchmarks",
75+
"pallet-communities/runtime-benchmarks",
76+
"pallet-nfts/runtime-benchmarks",
77+
"pallet-ranked-collective/runtime-benchmarks",
78+
"pallet-referenda-tracks/runtime-benchmarks",
79+
"pallet-referenda/runtime-benchmarks",
80+
"pallet-scheduler/runtime-benchmarks",
81+
"sp-runtime/runtime-benchmarks",
82+
]
83+
try-runtime = [
84+
"frame-support/try-runtime",
85+
"frame-system/try-runtime",
86+
"pallet-assets/try-runtime",
87+
"pallet-balances/try-runtime",
88+
"pallet-nfts/try-runtime",
89+
"pallet-ranked-collective/try-runtime",
90+
"pallet-referenda-tracks/try-runtime",
91+
"pallet-referenda/try-runtime",
92+
"pallet-scheduler/try-runtime",
93+
"sp-runtime/try-runtime",
94+
]

Diff for: pallets/communities-manager/src/benchmarking.rs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Benchmarking setup for pallet-communities
2+
use super::*;
3+
4+
use frame_benchmarking::v2::*;
5+
6+
use frame_support::traits::fungible::Mutate;
7+
use frame_system::RawOrigin;
8+
use sp_runtime::traits::StaticLookup;
9+
10+
type RuntimeEventFor<T> = <T as Config>::RuntimeEvent;
11+
12+
fn assert_has_event<T: Config>(generic_event: RuntimeEventFor<T>) {
13+
frame_system::Pallet::<T>::assert_has_event(generic_event.into());
14+
}
15+
16+
fn setup_account<T: Config>(who: &AccountIdOf<T>) -> Result<(), BenchmarkError>
17+
where
18+
NativeBalanceOf<T>: From<u128>,
19+
{
20+
let initial_balance: NativeBalanceOf<T> = 1_000_000_000_000_000u128.into();
21+
T::Balances::mint_into(who, initial_balance)?;
22+
Ok(())
23+
}
24+
25+
#[benchmarks(
26+
where
27+
RuntimeEventFor<T>: From<pallet_communities::Event<T>>,
28+
NativeBalanceOf<T>: From<u128>,
29+
BlockNumberFor<T>: From<u32>,
30+
CommunityIdOf<T>: From<u16>,
31+
)]
32+
mod benchmarks {
33+
use super::*;
34+
35+
#[benchmark]
36+
fn register() -> Result<(), BenchmarkError> {
37+
// setup code
38+
let first_member: AccountIdOf<T> = frame_benchmarking::account("founder", 0, 0);
39+
setup_account::<T>(&first_member)?;
40+
41+
let community_id: CommunityIdOf<T> = 1.into();
42+
let admin_origin: RuntimeOriginFor<T> = frame_system::Origin::<T>::Signed(first_member.clone()).into();
43+
let admin_origin_caller: PalletsOriginOf<T> = admin_origin.into_caller();
44+
45+
#[extrinsic_call]
46+
_(
47+
RawOrigin::Root,
48+
community_id,
49+
BoundedVec::truncate_from(b"Test Community".into()),
50+
Some(admin_origin_caller.clone()),
51+
None,
52+
Some(T::Lookup::unlookup(first_member)),
53+
);
54+
55+
// verification code
56+
assert_has_event::<T>(Event::<T>::CommunityRegistered { id: community_id }.into());
57+
Ok(())
58+
}
59+
60+
impl_benchmark_test_suite!(
61+
Pallet,
62+
sp_io::TestExternalities::new(Default::default()),
63+
crate::mock::Test
64+
);
65+
}

Diff for: pallets/communities-manager/src/lib.rs

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
pub use pallet::*;
4+
5+
#[cfg(feature = "runtime-benchmarks")]
6+
mod benchmarking;
7+
8+
#[cfg(test)]
9+
pub(crate) mod mock;
10+
#[cfg(test)]
11+
mod tests;
12+
13+
pub mod weights;
14+
pub use weights::*;
15+
16+
use fc_traits_tracks::MutateTracks;
17+
use frame_support::{
18+
pallet_prelude::*,
19+
traits::{nonfungibles_v2::Create, OriginTrait, RankedMembers},
20+
};
21+
use frame_system::pallet_prelude::{BlockNumberFor, OriginFor};
22+
use pallet_communities::{
23+
types::{
24+
AccountIdLookupOf, AccountIdOf, CommunityIdOf, DecisionMethodFor, NativeBalanceOf, PalletsOriginOf,
25+
RuntimeOriginFor,
26+
},
27+
Origin as CommunityOrigin,
28+
};
29+
use pallet_nfts::CollectionConfig;
30+
use pallet_referenda::{TrackInfo, TracksInfo};
31+
32+
type TrackInfoOf<T> = TrackInfo<NativeBalanceOf<T>, BlockNumberFor<T>>;
33+
34+
#[frame_support::pallet]
35+
pub mod pallet {
36+
use sp_runtime::str_array;
37+
38+
use super::*;
39+
40+
type CommunityName = BoundedVec<u8, ConstU32<25>>;
41+
42+
/// Configure the pallet by specifying the parameters and types on which it
43+
/// depends.
44+
#[pallet::config]
45+
pub trait Config: frame_system::Config + pallet_communities::Config {
46+
/// Because this pallet emits events, it depends on the runtime's
47+
/// definition of an event.
48+
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
49+
50+
type CreateCollection: Create<
51+
AccountIdOf<Self>,
52+
CollectionConfig<NativeBalanceOf<Self>, BlockNumberFor<Self>, CommunityIdOf<Self>>,
53+
CollectionId = CommunityIdOf<Self>,
54+
>;
55+
56+
type Tracks: TracksInfo<NativeBalanceOf<Self>, BlockNumberFor<Self>>
57+
+ MutateTracks<
58+
NativeBalanceOf<Self>,
59+
BlockNumberFor<Self>,
60+
Id = CommunityIdOf<Self>,
61+
RuntimeOrigin = PalletsOriginOf<Self>,
62+
>;
63+
64+
type RankedCollective: RankedMembers<AccountId = AccountIdOf<Self>>;
65+
66+
/// Type representing the weight of this pallet
67+
type WeightInfo: WeightInfo;
68+
69+
// #[cfg(feature = "runtime-benchmarks")]
70+
// type BenchmarkHelper: BenchmarkHelper<Self>;
71+
}
72+
73+
#[pallet::pallet]
74+
pub struct Pallet<T>(_);
75+
76+
// Pallets use events to inform users when important changes are made.
77+
// https://docs.substrate.io/main-docs/build/events-errors/
78+
#[pallet::event]
79+
#[pallet::generate_deposit(pub(super) fn deposit_event)]
80+
pub enum Event<T: Config> {
81+
/// The community with [`CommmunityId`](pallet_communities::CommunityId)
82+
/// has been created.
83+
CommunityRegistered { id: T::CommunityId },
84+
}
85+
86+
// Errors inform users that something worked or went wrong.
87+
#[pallet::error]
88+
pub enum Error<T> {
89+
/// Community name didn't contain valid utf8 characters
90+
InvalidCommunityName,
91+
/// It was not possible to register the community
92+
CannotRegister,
93+
}
94+
95+
// Dispatchable functions allows users to interact with the pallet and invoke
96+
// state changes. These functions materialize as "extrinsics", which are often
97+
// compared to transactions. Dispatchable functions must be annotated with a
98+
// weight and must return a DispatchResult.
99+
#[pallet::call(weight(<T as Config>::WeightInfo))]
100+
impl<T: Config> Pallet<T> {
101+
#[pallet::call_index(0)]
102+
pub fn register(
103+
origin: OriginFor<T>,
104+
community_id: CommunityIdOf<T>,
105+
name: CommunityName,
106+
maybe_admin_origin: Option<PalletsOriginOf<T>>,
107+
maybe_decision_method: Option<DecisionMethodFor<T>>,
108+
_maybe_first_member: Option<AccountIdLookupOf<T>>,
109+
) -> DispatchResult {
110+
let maybe_deposit = T::CreateOrigin::ensure_origin(origin)?;
111+
112+
let community_name = core::str::from_utf8(&name).map_err(|_| Error::<T>::InvalidCommunityName)?;
113+
let community_origin: RuntimeOriginFor<T> = CommunityOrigin::<T>::new(community_id).into();
114+
let admin_origin = maybe_admin_origin.unwrap_or(community_origin.clone().into_caller());
115+
// Register first to check if community exists
116+
pallet_communities::Pallet::<T>::register(&admin_origin, &community_id, maybe_deposit)?;
117+
118+
if let Some(decision_method) = maybe_decision_method {
119+
pallet_communities::Pallet::<T>::set_decision_method(
120+
admin_origin.clone().into(),
121+
community_id,
122+
decision_method,
123+
)?;
124+
}
125+
126+
let community_account = pallet_communities::Pallet::<T>::community_account(&community_id);
127+
128+
// Create memberships collection for community
129+
T::CreateCollection::create_collection_with_id(
130+
community_id,
131+
&community_account,
132+
&community_account,
133+
&CollectionConfig {
134+
settings: Default::default(),
135+
max_supply: None,
136+
mint_settings: Default::default(),
137+
},
138+
)?;
139+
140+
// Create governance track for community
141+
T::Tracks::insert(
142+
community_id,
143+
Self::default_tack(community_name),
144+
community_origin.into_caller(),
145+
)?;
146+
// Induct community at Kreivo Governance with rank 1
147+
T::RankedCollective::induct(&community_account)?;
148+
149+
Self::deposit_event(Event::<T>::CommunityRegistered { id: community_id });
150+
Ok(())
151+
}
152+
}
153+
154+
impl<T: Config> Pallet<T> {
155+
fn default_tack(name: &str) -> TrackInfoOf<T> {
156+
use sp_runtime::Perbill;
157+
TrackInfo {
158+
name: str_array(name),
159+
max_deciding: 1,
160+
decision_deposit: 0u8.into(),
161+
prepare_period: 1u8.into(),
162+
decision_period: u8::MAX.into(),
163+
confirm_period: 1u8.into(),
164+
min_enactment_period: 1u8.into(),
165+
min_approval: pallet_referenda::Curve::LinearDecreasing {
166+
length: Perbill::from_percent(100),
167+
floor: Perbill::from_percent(50),
168+
ceil: Perbill::from_percent(100),
169+
},
170+
min_support: pallet_referenda::Curve::LinearDecreasing {
171+
length: Perbill::from_percent(100),
172+
floor: Perbill::from_percent(0),
173+
ceil: Perbill::from_percent(50),
174+
},
175+
}
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)