Skip to content

Commit

Permalink
Automatically create the asset of a community if it doesnt exist yet
Browse files Browse the repository at this point in the history
  • Loading branch information
olanod committed May 14, 2024
1 parent ff7d85c commit abe6837
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 48 deletions.
7 changes: 5 additions & 2 deletions pallets/communities/src/functions.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{origin::DecisionMethod, *};
use super::*;
use fc_traits_memberships::{GenericRank, Inspect, Rank};
use frame_support::{
dispatch::PostDispatchInfo,
Expand Down Expand Up @@ -95,7 +95,10 @@ impl<T: Config> Pallet<T> {
};

let say = *match (vote, decision_method) {
(Vote::AssetBalance(say, asset, ..), DecisionMethod::CommunityAsset(a)) if asset == a => say,
(Vote::AssetBalance(say, asset, amount), DecisionMethod::CommunityAsset(a, min)) if asset == a => {
ensure!(amount > min, Error::<T>::VoteBelowMinimum);
say
}
(Vote::NativeBalance(say, ..), DecisionMethod::NativeToken)
| (Vote::Standard(say), DecisionMethod::Membership | DecisionMethod::Rank) => say,
_ => fail!(Error::<T>::InvalidVoteType),
Expand Down
21 changes: 15 additions & 6 deletions pallets/communities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,8 @@ pub mod pallet {
Blake2_128Concat, Parameter,
};
use frame_system::pallet_prelude::{ensure_signed, BlockNumberFor, OriginFor};
use sp_runtime::{
traits::{Dispatchable, StaticLookup},
TokenError,
};
use sp_runtime::traits::AccountIdConversion;
use sp_runtime::traits::{Dispatchable, StaticLookup};
use sp_std::prelude::Box;

const ONE: NonZeroU8 = NonZeroU8::MIN;
Expand Down Expand Up @@ -193,7 +191,7 @@ pub mod pallet {
>;

/// Type represents interactions between fungibles (i.e. assets)
type Assets: fungibles::Inspect<Self::AccountId>
type Assets: fungibles::Inspect<Self::AccountId, Balance = NativeBalanceOf<Self>>
+ fungibles::Mutate<Self::AccountId>
+ fungibles::Create<Self::AccountId>
+ fungibles::hold::Inspect<Self::AccountId, Reason = Self::RuntimeHoldReason>
Expand Down Expand Up @@ -351,6 +349,8 @@ pub mod pallet {
NoLocksInPlace,
/// The origin already controls another community
AlreadyAdmin,
/// The vote is below the minimum requried
VoteBelowMinimum,
}

// Dispatchable functions allows users to interact with the pallet and invoke
Expand Down Expand Up @@ -477,6 +477,15 @@ pub mod pallet {
decision_method: DecisionMethodFor<T>,
) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
if let DecisionMethod::CommunityAsset(ref asset, min_vote) = decision_method {
// best effort attemt to create the asset if it doesn't exist
let _ = <T::Assets as fungibles::Create<T::AccountId>>::create(
asset.clone(),
T::PalletId::get().into_account_truncating(),
false,
min_vote,
);
}
CommunityDecisionMethod::<T>::set(community_id, decision_method);
Self::deposit_event(Event::DecisionMethodSet { id: community_id });
Ok(())
Expand All @@ -490,7 +499,7 @@ pub mod pallet {
#[pallet::compact] poll_index: PollIndexOf<T>,
vote: VoteOf<T>,
) -> DispatchResult {
ensure!(VoteWeight::from(&vote).gt(&0), TokenError::BelowMinimum);
ensure!(VoteWeight::from(&vote).gt(&0), Error::<T>::VoteBelowMinimum);
let who = ensure_signed(origin)?;
let community_id = T::MemberMgmt::check_membership(&who, &membership_id).ok_or(Error::<T>::NotAMember)?;
let decision_method = CommunityDecisionMethod::<T>::get(community_id);
Expand Down
7 changes: 4 additions & 3 deletions pallets/communities/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ pub use virto_common::{CommunityId, MembershipId};

use crate::{
self as pallet_communities,
origin::{DecisionMethod, EnsureCommunity, EnsureSignedPays},
origin::{EnsureCommunity, EnsureSignedPays},
types::{Tally, VoteWeight},
DecisionMethod,
};

// Weights constants
Expand Down Expand Up @@ -455,7 +456,7 @@ pub(crate) struct TestEnvBuilder {
assets_config: AssetsConfig,
balances: Vec<(AccountId, Balance)>,
communities: Vec<CommunityId>,
decision_methods: sp_std::collections::btree_map::BTreeMap<CommunityId, DecisionMethod<AssetId>>,
decision_methods: sp_std::collections::btree_map::BTreeMap<CommunityId, DecisionMethod<AssetId, Balance>>,
members: Vec<(CommunityId, AccountId)>,
memberships: Vec<(CommunityId, MembershipId)>,
tracks: Vec<(TrackIdOf<Test, ()>, TrackInfoOf<Test>)>,
Expand Down Expand Up @@ -498,7 +499,7 @@ impl TestEnvBuilder {
pub(crate) fn add_community(
mut self,
community_id: CommunityId,
decision_method: DecisionMethod<AssetId>,
decision_method: DecisionMethod<AssetId, Balance>,
members: &[AccountId],
memberships: &[MembershipId],
maybe_track: Option<TrackInfoOf<Test>>,
Expand Down
10 changes: 0 additions & 10 deletions pallets/communities/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,6 @@ pub enum Subset<T: Config> {
AtLeastRank(GenericRank),
}

/// The mechanism used by the community or one of its subsets to make decisions
#[derive(Clone, Debug, Decode, Default, Encode, Eq, MaxEncodedLen, PartialEq, TypeInfo)]
pub enum DecisionMethod<AssetId> {
#[default]
Membership,
NativeToken,
CommunityAsset(AssetId),
Rank,
}

#[cfg(feature = "xcm")]
impl<T> TryConvert<RuntimeOriginFor<T>, xcm::v3::MultiLocation> for RawOrigin<T>
where
Expand Down
68 changes: 44 additions & 24 deletions pallets/communities/src/tests/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use parity_scale_codec::Encode;
use sp_runtime::{str_array as s, BoundedVec, TokenError};

use crate::{
origin::DecisionMethod,
types::{Tally, Vote},
Call,
Call, DecisionMethod,
};
use frame_support::assert_noop;
use pallet_referenda::TrackInfo;
Expand Down Expand Up @@ -108,7 +107,7 @@ fn new_test_ext() -> sp_io::TestExternalities {
// Community-asset based
.add_community(
COMMUNITY_B,
DecisionMethod::CommunityAsset(COMMUNITY_B_ASSET_ID),
DecisionMethod::CommunityAsset(COMMUNITY_B_ASSET_ID, 10),
&[BOB, CHARLIE],
memberships_of(COMMUNITY_B),
Some(CommunityTrack::get()),
Expand All @@ -119,7 +118,7 @@ fn new_test_ext() -> sp_io::TestExternalities {
true,
1,
None,
Some(vec![(BOB, 10), (CHARLIE, 10)]),
Some(vec![(BOB, 50), (CHARLIE, 50)]),
)
// Native-asset based
.add_community(
Expand Down Expand Up @@ -210,7 +209,7 @@ mod vote {
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 0)
),
TokenError::BelowMinimum
Error::VoteBelowMinimum
);
});
}
Expand Down Expand Up @@ -537,13 +536,34 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 10)
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 50)
),
TokenError::FundsUnavailable
);
});
}

#[test]
fn fails_if_asset_vote_weight_is_under_minimum() {
new_test_ext().execute_with(|| {
assert_noop!(
Communities::vote(
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 10)
),
Error::VoteBelowMinimum
);
assert_ok!(Communities::vote(
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 11)
));
});
}

#[test]
fn holds_cannot_overlap() {
new_test_ext().execute_with(|| {
Expand All @@ -552,7 +572,7 @@ mod vote {
COMMUNITY_B_ASSET_ID,
&pallet_preimage::HoldReason::Preimage.into(),
&CHARLIE,
6,
40,
));

// Before voting, the poll is ongoing
Expand All @@ -561,7 +581,7 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 5)
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 15)
),
TokenError::FundsUnavailable
);
Expand Down Expand Up @@ -589,7 +609,7 @@ mod vote {
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 6)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 30)
));

tick_block();
Expand All @@ -598,7 +618,7 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 6)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 30)
));

tick_block();
Expand All @@ -611,9 +631,9 @@ mod vote {
pallet_referenda::Event::<Test>::Confirmed {
index: 1,
tally: Tally {
ayes: 12,
ayes: 60,
nays: 0,
bare_ayes: 12,
bare_ayes: 60,
..Default::default()
},
}
Expand Down Expand Up @@ -643,7 +663,7 @@ mod vote {
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 2)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 12)
));

tick_block();
Expand All @@ -652,7 +672,7 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 1)
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 11)
));

tick_blocks(4);
Expand All @@ -665,9 +685,9 @@ mod vote {
pallet_referenda::Event::<Test>::Confirmed {
index: 1,
tally: Tally {
ayes: 2,
nays: 1,
bare_ayes: 2,
ayes: 12,
nays: 11,
bare_ayes: 12,
..Default::default()
},
}
Expand Down Expand Up @@ -699,7 +719,7 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 6)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 11)
));

tick_block();
Expand All @@ -708,7 +728,7 @@ mod vote {
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 7)
Vote::AssetBalance(false, COMMUNITY_B_ASSET_ID, 12)
));

tick_block();
Expand All @@ -717,7 +737,7 @@ mod vote {
RuntimeOrigin::signed(CHARLIE),
membership(COMMUNITY_B, 2),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 8)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 13)
));

tick_blocks(3);
Expand All @@ -726,9 +746,9 @@ mod vote {
pallet_referenda::Event::<Test>::Confirmed {
index: 1,
tally: Tally {
ayes: 8,
nays: 7,
bare_ayes: 8,
ayes: 13,
nays: 12,
bare_ayes: 13,
..Default::default()
},
}
Expand Down Expand Up @@ -1156,7 +1176,7 @@ mod unlock {
RuntimeOrigin::signed(BOB),
membership(COMMUNITY_B, 1),
1,
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 9)
Vote::AssetBalance(true, COMMUNITY_B_ASSET_ID, 15)
));

assert_ok!(Communities::vote(
Expand Down
15 changes: 12 additions & 3 deletions pallets/communities/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::origin::DecisionMethod;
use crate::{CommunityDecisionMethod, Config};
use fc_traits_memberships::{Inspect, Rank};
use frame_support::pallet_prelude::*;
Expand All @@ -16,7 +15,7 @@ pub type NativeBalanceOf<T> = <<T as Config>::Balances as fungible::Inspect<Acco
pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type CommunityIdOf<T> = <T as Config>::CommunityId;
pub type VoteOf<T> = Vote<AssetIdOf<T>, AssetBalanceOf<T>, NativeBalanceOf<T>>;
pub type DecisionMethodFor<T> = DecisionMethod<AssetIdOf<T>>;
pub type DecisionMethodFor<T> = DecisionMethod<AssetIdOf<T>, AssetBalanceOf<T>>;
pub type PollIndexOf<T> = <<T as Config>::Polls as Polling<Tally<T>>>::Index;
pub type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
pub type PalletsOriginOf<T> =
Expand Down Expand Up @@ -54,6 +53,16 @@ pub enum CommunityState {
Blocked,
}

/// The mechanism used by the community or one of its subsets to make decisions
#[derive(Clone, Debug, Decode, Default, Encode, Eq, MaxEncodedLen, PartialEq, TypeInfo)]
pub enum DecisionMethod<AssetId, MinVote> {
#[default]
Membership,
NativeToken,
CommunityAsset(AssetId, MinVote),
Rank,
}

// Governance
pub type VoteWeight = u32;

Expand Down Expand Up @@ -126,7 +135,7 @@ impl<T: Config> Tally<T> {
DecisionMethod::Membership => T::MemberMgmt::members_total(&community_id),
DecisionMethod::Rank => T::MemberMgmt::ranks_total(&community_id),
DecisionMethod::NativeToken => T::Balances::total_issuance().saturated_into::<VoteWeight>(),
DecisionMethod::CommunityAsset(asset_id) => {
DecisionMethod::CommunityAsset(asset_id, _) => {
T::Assets::total_issuance(asset_id).saturated_into::<VoteWeight>()
}
}
Expand Down

0 comments on commit abe6837

Please sign in to comment.