Skip to content

Commit

Permalink
[Communities] Permissionless Registering and Management of Communities (
Browse files Browse the repository at this point in the history
#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
5 people authored Apr 22, 2024
1 parent e7a0a44 commit 2722936
Show file tree
Hide file tree
Showing 34 changed files with 1,520 additions and 584 deletions.
216 changes: 127 additions & 89 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ pallet-asset-registry = { default-features = false, path = "pallets/asset-regist
pallet-burner = { default-features = false, path = "pallets/burner" }
pallet-payments = { default-features = false, path = "pallets/payments" }
pallet-communities = { default-features = false, path = "pallets/communities" }
pallet-communities-manager = { default-features = false, path = "pallets/communities-manager" }

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

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

# Substrate std
try-runtime-cli = { git = "https://github.com/virto-network/polkadot-sdk", branch = "release-virto-v1.5.0" }
Expand Down
2 changes: 1 addition & 1 deletion node/Cargo.toml
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'
Expand Down
94 changes: 94 additions & 0 deletions pallets/communities-manager/Cargo.toml
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",
]
65 changes: 65 additions & 0 deletions pallets/communities-manager/src/benchmarking.rs
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
);
}
178 changes: 178 additions & 0 deletions pallets/communities-manager/src/lib.rs
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),
},
}
}
}
}
Loading

0 comments on commit 2722936

Please sign in to comment.