-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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>
- Loading branch information
1 parent
e7a0a44
commit 2722936
Showing
34 changed files
with
1,520 additions
and
584 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "virto-node" | ||
version = "0.10.2" | ||
version = "0.11.0" | ||
authors = ['Virto Team <[email protected]>'] | ||
license = "GPL-3.0-only" | ||
homepage = 'https://github.com/virto-network/virto-node' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
[package] | ||
name = "pallet-communities-manager" | ||
version = "0.1.0" | ||
authors = ["Virto Team<[email protected]>"] | ||
description = "This pallet helps with all the necesary steps to correctly setup a community." | ||
license = "MIT-0" | ||
homepage = 'https://github.com/virto-network/virto-node' | ||
repository = 'https://github.com/virto-network/virto-node' | ||
edition = "2021" | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[dependencies] | ||
fc-traits-tracks = { workspace = true } | ||
|
||
frame-benchmarking = { workspace = true, optional = true } | ||
frame-support = { workspace = true } | ||
frame-system = { workspace = true } | ||
|
||
pallet-communities = { workspace = true } | ||
pallet-nfts = { workspace = true } | ||
pallet-referenda = { workspace = true } | ||
|
||
log = { workspace = true } | ||
|
||
parity-scale-codec = { workspace = true, features = ["derive"] } | ||
scale-info = { workspace = true, features = ["derive"] } | ||
|
||
sp-runtime = { workspace = true } | ||
sp-std = { workspace = true } | ||
|
||
[dev-dependencies] | ||
sp-core = { workspace = true } | ||
sp-io = { workspace = true } | ||
|
||
pallet-assets = { workspace = true } | ||
pallet-balances = { workspace = true } | ||
pallet-ranked-collective = { workspace = true } | ||
pallet-referenda-tracks = { workspace = true } | ||
pallet-scheduler = { workspace = true } | ||
virto-common = { workspace = true, default-features = false, features = ["runtime"] } | ||
|
||
[features] | ||
default = ["std", "testnet"] | ||
testnet = [] | ||
std = [ | ||
"fc-traits-tracks/std", | ||
"frame-benchmarking?/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"log/std", | ||
"pallet-assets/std", | ||
"pallet-balances/std", | ||
"pallet-communities/std", | ||
"pallet-nfts/std", | ||
"pallet-ranked-collective/std", | ||
"pallet-referenda-tracks/std", | ||
"pallet-referenda/std", | ||
"pallet-scheduler/std", | ||
"parity-scale-codec/std", | ||
"scale-info/std", | ||
"sp-core/std", | ||
"sp-io/std", | ||
"sp-runtime/std", | ||
"sp-std/std", | ||
"virto-common/std", | ||
] | ||
runtime-benchmarks = [ | ||
"frame-benchmarking/runtime-benchmarks", | ||
"frame-support/runtime-benchmarks", | ||
"frame-system/runtime-benchmarks", | ||
"pallet-assets/runtime-benchmarks", | ||
"pallet-balances/runtime-benchmarks", | ||
"pallet-communities/runtime-benchmarks", | ||
"pallet-nfts/runtime-benchmarks", | ||
"pallet-ranked-collective/runtime-benchmarks", | ||
"pallet-referenda-tracks/runtime-benchmarks", | ||
"pallet-referenda/runtime-benchmarks", | ||
"pallet-scheduler/runtime-benchmarks", | ||
"sp-runtime/runtime-benchmarks", | ||
] | ||
try-runtime = [ | ||
"frame-support/try-runtime", | ||
"frame-system/try-runtime", | ||
"pallet-assets/try-runtime", | ||
"pallet-balances/try-runtime", | ||
"pallet-nfts/try-runtime", | ||
"pallet-ranked-collective/try-runtime", | ||
"pallet-referenda-tracks/try-runtime", | ||
"pallet-referenda/try-runtime", | ||
"pallet-scheduler/try-runtime", | ||
"sp-runtime/try-runtime", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
//! Benchmarking setup for pallet-communities | ||
use super::*; | ||
|
||
use frame_benchmarking::v2::*; | ||
|
||
use frame_support::traits::fungible::Mutate; | ||
use frame_system::RawOrigin; | ||
use sp_runtime::traits::StaticLookup; | ||
|
||
type RuntimeEventFor<T> = <T as Config>::RuntimeEvent; | ||
|
||
fn assert_has_event<T: Config>(generic_event: RuntimeEventFor<T>) { | ||
frame_system::Pallet::<T>::assert_has_event(generic_event.into()); | ||
} | ||
|
||
fn setup_account<T: Config>(who: &AccountIdOf<T>) -> Result<(), BenchmarkError> | ||
where | ||
NativeBalanceOf<T>: From<u128>, | ||
{ | ||
let initial_balance: NativeBalanceOf<T> = 1_000_000_000_000_000u128.into(); | ||
T::Balances::mint_into(who, initial_balance)?; | ||
Ok(()) | ||
} | ||
|
||
#[benchmarks( | ||
where | ||
RuntimeEventFor<T>: From<pallet_communities::Event<T>>, | ||
NativeBalanceOf<T>: From<u128>, | ||
BlockNumberFor<T>: From<u32>, | ||
CommunityIdOf<T>: From<u16>, | ||
)] | ||
mod benchmarks { | ||
use super::*; | ||
|
||
#[benchmark] | ||
fn register() -> Result<(), BenchmarkError> { | ||
// setup code | ||
let first_member: AccountIdOf<T> = frame_benchmarking::account("founder", 0, 0); | ||
setup_account::<T>(&first_member)?; | ||
|
||
let community_id: CommunityIdOf<T> = 1.into(); | ||
let admin_origin: RuntimeOriginFor<T> = frame_system::Origin::<T>::Signed(first_member.clone()).into(); | ||
let admin_origin_caller: PalletsOriginOf<T> = admin_origin.into_caller(); | ||
|
||
#[extrinsic_call] | ||
_( | ||
RawOrigin::Root, | ||
community_id, | ||
BoundedVec::truncate_from(b"Test Community".into()), | ||
Some(admin_origin_caller.clone()), | ||
None, | ||
Some(T::Lookup::unlookup(first_member)), | ||
); | ||
|
||
// verification code | ||
assert_has_event::<T>(Event::<T>::CommunityRegistered { id: community_id }.into()); | ||
Ok(()) | ||
} | ||
|
||
impl_benchmark_test_suite!( | ||
Pallet, | ||
sp_io::TestExternalities::new(Default::default()), | ||
crate::mock::Test | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
pub use pallet::*; | ||
|
||
#[cfg(feature = "runtime-benchmarks")] | ||
mod benchmarking; | ||
|
||
#[cfg(test)] | ||
pub(crate) mod mock; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
pub mod weights; | ||
pub use weights::*; | ||
|
||
use fc_traits_tracks::MutateTracks; | ||
use frame_support::{ | ||
pallet_prelude::*, | ||
traits::{nonfungibles_v2::Create, OriginTrait, RankedMembers}, | ||
}; | ||
use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; | ||
use pallet_communities::{ | ||
types::{ | ||
AccountIdLookupOf, AccountIdOf, CommunityIdOf, DecisionMethodFor, NativeBalanceOf, PalletsOriginOf, | ||
RuntimeOriginFor, | ||
}, | ||
Origin as CommunityOrigin, | ||
}; | ||
use pallet_nfts::CollectionConfig; | ||
use pallet_referenda::{TrackInfo, TracksInfo}; | ||
|
||
type TrackInfoOf<T> = TrackInfo<NativeBalanceOf<T>, BlockNumberFor<T>>; | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use sp_runtime::str_array; | ||
|
||
use super::*; | ||
|
||
type CommunityName = BoundedVec<u8, ConstU32<25>>; | ||
|
||
/// Configure the pallet by specifying the parameters and types on which it | ||
/// depends. | ||
#[pallet::config] | ||
pub trait Config: frame_system::Config + pallet_communities::Config { | ||
/// Because this pallet emits events, it depends on the runtime's | ||
/// definition of an event. | ||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; | ||
|
||
type CreateCollection: Create< | ||
AccountIdOf<Self>, | ||
CollectionConfig<NativeBalanceOf<Self>, BlockNumberFor<Self>, CommunityIdOf<Self>>, | ||
CollectionId = CommunityIdOf<Self>, | ||
>; | ||
|
||
type Tracks: TracksInfo<NativeBalanceOf<Self>, BlockNumberFor<Self>> | ||
+ MutateTracks< | ||
NativeBalanceOf<Self>, | ||
BlockNumberFor<Self>, | ||
Id = CommunityIdOf<Self>, | ||
RuntimeOrigin = PalletsOriginOf<Self>, | ||
>; | ||
|
||
type RankedCollective: RankedMembers<AccountId = AccountIdOf<Self>>; | ||
|
||
/// Type representing the weight of this pallet | ||
type WeightInfo: WeightInfo; | ||
|
||
// #[cfg(feature = "runtime-benchmarks")] | ||
// type BenchmarkHelper: BenchmarkHelper<Self>; | ||
} | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(_); | ||
|
||
// Pallets use events to inform users when important changes are made. | ||
// https://docs.substrate.io/main-docs/build/events-errors/ | ||
#[pallet::event] | ||
#[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
pub enum Event<T: Config> { | ||
/// The community with [`CommmunityId`](pallet_communities::CommunityId) | ||
/// has been created. | ||
CommunityRegistered { id: T::CommunityId }, | ||
} | ||
|
||
// Errors inform users that something worked or went wrong. | ||
#[pallet::error] | ||
pub enum Error<T> { | ||
/// Community name didn't contain valid utf8 characters | ||
InvalidCommunityName, | ||
/// It was not possible to register the community | ||
CannotRegister, | ||
} | ||
|
||
// Dispatchable functions allows users to interact with the pallet and invoke | ||
// state changes. These functions materialize as "extrinsics", which are often | ||
// compared to transactions. Dispatchable functions must be annotated with a | ||
// weight and must return a DispatchResult. | ||
#[pallet::call(weight(<T as Config>::WeightInfo))] | ||
impl<T: Config> Pallet<T> { | ||
#[pallet::call_index(0)] | ||
pub fn register( | ||
origin: OriginFor<T>, | ||
community_id: CommunityIdOf<T>, | ||
name: CommunityName, | ||
maybe_admin_origin: Option<PalletsOriginOf<T>>, | ||
maybe_decision_method: Option<DecisionMethodFor<T>>, | ||
_maybe_first_member: Option<AccountIdLookupOf<T>>, | ||
) -> DispatchResult { | ||
let maybe_deposit = T::CreateOrigin::ensure_origin(origin)?; | ||
|
||
let community_name = core::str::from_utf8(&name).map_err(|_| Error::<T>::InvalidCommunityName)?; | ||
let community_origin: RuntimeOriginFor<T> = CommunityOrigin::<T>::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::<T>::register(&admin_origin, &community_id, maybe_deposit)?; | ||
|
||
if let Some(decision_method) = maybe_decision_method { | ||
pallet_communities::Pallet::<T>::set_decision_method( | ||
admin_origin.clone().into(), | ||
community_id, | ||
decision_method, | ||
)?; | ||
} | ||
|
||
let community_account = pallet_communities::Pallet::<T>::community_account(&community_id); | ||
|
||
// Create memberships collection for community | ||
T::CreateCollection::create_collection_with_id( | ||
community_id, | ||
&community_account, | ||
&community_account, | ||
&CollectionConfig { | ||
settings: Default::default(), | ||
max_supply: None, | ||
mint_settings: Default::default(), | ||
}, | ||
)?; | ||
|
||
// Create governance track for community | ||
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)?; | ||
|
||
Self::deposit_event(Event::<T>::CommunityRegistered { id: community_id }); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<T: Config> Pallet<T> { | ||
fn default_tack(name: &str) -> TrackInfoOf<T> { | ||
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), | ||
}, | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.