Runtime: Polkadot Fellowship promotion/demotion periods, members activity and salaries (#2607)

* core fellowship

* core fellowship weights

* salary

* weights

* fellowship pot

* registration period 15 days

* use treasury account for salary pay, promotion origin

* decision period for tracks 30 days

* docs

* comment

* Couple of fixes and some refactoring

* Alter curves to be a bit more conservative

* Use `PayOverXcm` for fellowship salary payments

* Docs and remove unneeded code

* Fixes

* Move Fellowship stuff in line with whitepaper

* fix: induction by a single Fellow (not proficient)

* doc fix

* renames, pallet index, allow unpaid for salary pallet

* Fix budget units

* Fixes

* Test sovereign account for Fellowship salaries

* Nice address test

* Fixes

* test for PayOverXcm setup

* Update parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

---------

Co-authored-by: Gav <gavin@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Muharem Ismailov
2023-06-06 12:48:15 +02:00
committed by GitHub
parent 1d395b6c99
commit ce0dcd5741
19 changed files with 1177 additions and 177 deletions
@@ -19,42 +19,38 @@
pub(crate) mod migration;
mod origins;
mod tracks;
use cumulus_primitives_core::Junction::GeneralIndex;
use frame_system::EnsureNever;
pub use origins::{
pallet_origins as pallet_fellowship_origins, Fellows, FellowshipCandidates, FellowshipExperts,
FellowshipMasters,
pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt,
EnsureFellowship, Fellows, Masters, Members,
};
use xcm_builder::{AliasesIntoAccountId32, LocatableAssetId, PayOverXcm};
use crate::{
constants, impls::ToParentTreasury, weights, AccountId, Balance, Balances, BlockNumber,
FellowshipReferenda, GovernanceLocation, Preimage, RelayTreasuryAccount, Runtime, RuntimeCall,
RuntimeEvent, Scheduler, DAYS,
constants, impls::ToParentTreasury, weights, AccountId, Balance, Balances, FellowshipReferenda,
GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent,
Scheduler, DAYS,
};
use frame_support::{
parameter_types,
traits::{EitherOf, MapSuccess, TryMapSuccess},
traits::{EitherOf, EitherOfDiverse, MapSuccess},
};
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use polkadot_runtime_constants::xcm::body::FELLOWSHIP_ADMIN_INDEX;
use sp_arithmetic::traits::CheckedSub;
use sp_core::ConstU32;
use sp_runtime::{
morph_types,
traits::{AccountIdConversion, ConstU16, Replace, TypedGet},
};
use polkadot_runtime_constants::{time::HOURS, xcm::body::FELLOWSHIP_ADMIN_INDEX};
use sp_core::{ConstU128, ConstU32};
use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace};
use xcm::latest::BodyId;
use self::origins::EnsureFellowship;
/// The Fellowship members' ranks.
pub mod ranks {
use pallet_ranked_collective::Rank;
pub const CANDIDATES: Rank = 0;
pub const DAN_1: Rank = 1;
pub const DAN_1: Rank = 1; // aka Members.
pub const DAN_2: Rank = 2;
pub const DAN_3: Rank = 3; // aka Fellows.
pub const DAN_4: Rank = 4;
pub const DAN_5: Rank = 5; // aka Experts.
pub const DAN_4: Rank = 4; // aka Architects.
pub const DAN_5: Rank = 5;
pub const DAN_6: Rank = 6;
pub const DAN_7: Rank = 7; // aka Masters.
pub const DAN_8: Rank = 8;
@@ -62,9 +58,6 @@ pub mod ranks {
}
parameter_types! {
pub const AlarmInterval: BlockNumber = 1;
pub const SubmissionDeposit: Balance = 0;
pub const UndecidingTimeout: BlockNumber = 7 * DAYS;
// Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting.
pub ReferendaPalletAccount: AccountId = constants::account::REFERENDA_PALLET_ID.into_account_truncating();
pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
@@ -80,63 +73,146 @@ impl pallet_referenda::Config<FellowshipReferendaInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type Scheduler = Scheduler;
type Currency = Balances;
// Fellows can submit proposals.
type SubmitOrigin =
pallet_ranked_collective::EnsureMember<Runtime, FellowshipCollectiveInstance, 1>;
type CancelOrigin = FellowshipExperts;
type KillOrigin = FellowshipMasters;
type Slash = ToParentTreasury<RelayTreasuryAccount, ReferendaPalletAccount, Runtime>;
pallet_ranked_collective::EnsureMember<Runtime, FellowshipCollectiveInstance, 3>;
type CancelOrigin = Architects;
type KillOrigin = Masters;
type Slash = ToParentTreasury<PolkadotTreasuryAccount, ReferendaPalletAccount, Runtime>;
type Votes = pallet_ranked_collective::Votes;
type Tally = pallet_ranked_collective::TallyOf<Runtime, FellowshipCollectiveInstance>;
type SubmissionDeposit = SubmissionDeposit;
type SubmissionDeposit = ConstU128<0>;
type MaxQueued = ConstU32<100>;
type UndecidingTimeout = UndecidingTimeout;
type AlarmInterval = AlarmInterval;
type UndecidingTimeout = ConstU32<{ 7 * DAYS }>;
type AlarmInterval = ConstU32<1>;
type Tracks = tracks::TracksInfo;
type Preimages = Preimage;
}
pub type FellowshipCollectiveInstance = pallet_ranked_collective::Instance1;
morph_types! {
/// A `TryMorph` implementation to reduce a scalar by a particular amount, checking for
/// underflow.
pub type CheckedReduceBy<N: TypedGet>: TryMorph = |r: N::Type| -> Result<N::Type, ()> {
r.checked_sub(&N::get()).ok_or(())
} where N::Type: CheckedSub;
}
impl pallet_ranked_collective::Config<FellowshipCollectiveInstance> for Runtime {
type WeightInfo = weights::pallet_ranked_collective::WeightInfo<Runtime>;
type RuntimeEvent = RuntimeEvent;
// Promotion is by any of:
// - Root can promote arbitrarily.
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a vote by the rank *above* the new rank.
type PromoteOrigin = EitherOf<
frame_system::EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>,
EitherOf<
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Replace<ConstU16<9>>,
>,
TryMapSuccess<EnsureFellowship, CheckedReduceBy<ConstU16<1>>>,
>,
>;
// Promotions and the induction of new members are serviced by `FellowshipCore` pallet instance.
type PromoteOrigin = EnsureNever<pallet_ranked_collective::Rank>;
// Demotion is by any of:
// - Root can demote arbitrarily.
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a vote by the rank two above the current rank.
type DemoteOrigin = EitherOf<
frame_system::EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>,
EitherOf<
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Replace<ConstU16<9>>,
>,
TryMapSuccess<EnsureFellowship, CheckedReduceBy<ConstU16<2>>>,
frame_system::EnsureRootWithSuccess<Self::AccountId, ConstU16<{ ranks::DAN_9 }>>,
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Replace<ConstU16<{ ranks::DAN_9 }>>,
>,
>;
type Polls = FellowshipReferenda;
type MinRankOfClass = sp_runtime::traits::Identity;
type MinRankOfClass = tracks::MinRankOfClass;
type VoteWeight = pallet_ranked_collective::Geometric;
}
pub type FellowshipCoreInstance = pallet_core_fellowship::Instance1;
impl pallet_core_fellowship::Config<FellowshipCoreInstance> for Runtime {
type WeightInfo = weights::pallet_core_fellowship::WeightInfo<Runtime>;
type RuntimeEvent = RuntimeEvent;
type Members = pallet_ranked_collective::Pallet<Runtime, FellowshipCollectiveInstance>;
type Balance = Balance;
// Parameters are set by any of:
// - Root;
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a vote among all Fellows.
type ParamsOrigin = EitherOfDiverse<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Fellows,
>;
// Induction (creating a candidate) is by any of:
// - Root;
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a single Fellow;
// - a vote among all Members.
type InductOrigin = EitherOfDiverse<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
EitherOfDiverse<
pallet_ranked_collective::EnsureMember<
Runtime,
FellowshipCollectiveInstance,
{ ranks::DAN_3 },
>,
Members,
>,
>;
// Approval (rank-retention) of a Member's current rank is by any of:
// - Root;
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a vote by the rank two above the current rank for all retention up to the Master rank.
type ApproveOrigin = EitherOf<
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Replace<ConstU16<{ ranks::DAN_9 }>>,
>,
EnsureCanRetainAt,
>;
// Promotion is by any of:
// - Root can promote arbitrarily.
// - the FellowshipAdmin origin (i.e. token holder referendum);
// - a vote by the rank two above the new rank for all promotions up to the Master rank.
type PromoteOrigin = EitherOf<
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, FellowshipAdminBodyId>>,
Replace<ConstU16<{ ranks::DAN_9 }>>,
>,
EnsureCanPromoteTo,
>;
type EvidenceSize = ConstU32<65536>;
}
pub type FellowshipSalaryInstance = pallet_salary::Instance1;
use xcm::prelude::*;
parameter_types! {
pub AssetHub: MultiLocation = (Parent, Parachain(1000)).into();
pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into();
pub UsdtAsset: LocatableAssetId = LocatableAssetId {
location: AssetHub::get(),
asset_id: AssetHubUsdtId::get(),
};
// The interior location on AssetHub for the paying account. This is the Fellowship Salary
// pallet instance (which sits at index 64). This sovereign account will need funding.
pub Interior: InteriorMultiLocation = PalletInstance(64).into();
}
const USDT_UNITS: u128 = 1_000_000;
/// [`PayOverXcm`] setup to pay the Fellowship salary on the AssetHub in USDT.
pub type FellowshipSalaryPaymaster = PayOverXcm<
Interior,
crate::xcm_config::XcmRouter,
crate::PolkadotXcm,
ConstU32<{ 6 * HOURS }>,
AccountId,
(),
ConvertToValue<UsdtAsset>,
AliasesIntoAccountId32<(), AccountId>,
>;
impl pallet_salary::Config<FellowshipSalaryInstance> for Runtime {
type WeightInfo = weights::pallet_salary::WeightInfo<Runtime>;
type RuntimeEvent = RuntimeEvent;
type Paymaster = FellowshipSalaryPaymaster;
type Members = pallet_ranked_collective::Pallet<Runtime, FellowshipCollectiveInstance>;
#[cfg(not(feature = "runtime-benchmarks"))]
type Salary = pallet_core_fellowship::Pallet<Runtime, FellowshipCoreInstance>;
#[cfg(feature = "runtime-benchmarks")]
type Salary = frame_support::traits::tokens::ConvertRank<
crate::impls::benchmarks::RankToSalary<Balances>,
>;
// 15 days to register for a salary payment.
type RegistrationPeriod = ConstU32<{ 15 * DAYS }>;
// 15 days to claim the salary payment.
type PayoutPeriod = ConstU32<{ 15 * DAYS }>;
// Total monthly salary budget.
type Budget = ConstU128<{ 100_000 * USDT_UNITS }>;
}