Westend: Fellowship Treasury (#2532)

Treasury Pallet Instance for the Fellowship in Westend Collectives.

In this update, we present a Treasury Pallet Instance that is under the
control of the Fellowship body, with oversight from the Root and
Treasurer origins. Here's how it is governed:
- the Root origin have the authority to reject or approve spend
proposals, with no amount limit for approvals.
- the Treasurer origin have the authority to reject or approve spend
proposals, with approval limits of up to 10,000,000 DOT.
- Voice of all Fellows ranked at 3 or above can reject or approve spend
proposals, with a maximum approval limit of 10,000 DOT.
- Voice of Fellows ranked at 4 or above can also reject or approve spend
proposals, with a maximum approval limit of 10,000,000 DOT.

Additionally, we introduce the Asset Rate Pallet Instance to establish
conversion rates from asset A to B. This is used to determine if a
proposed spend amount involving a non-native asset is permissible by the
commanding origin. The rates can be set up by the Root, Treasurer
origins, or Voice of all Fellows.

---------

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: joepetrowski <joe@parity.io>
This commit is contained in:
Muharem
2023-12-08 14:02:09 +01:00
committed by GitHub
parent 1bdfb29587
commit da40d97a23
26 changed files with 827 additions and 27 deletions
@@ -21,28 +21,41 @@ mod tracks;
use crate::{
impls::ToParentTreasury,
weights,
xcm_config::{FellowshipAdminBodyId, UsdtAssetHub},
AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, Runtime,
RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS,
xcm_config::{FellowshipAdminBodyId, TreasurerBodyId, UsdtAssetHub},
AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage,
Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS,
};
use frame_support::{
parameter_types,
traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg},
traits::{
EitherOf, EitherOfDiverse, MapSuccess, NeverEnsureOrigin, OriginTrait, TryWithMorphedArg,
},
PalletId,
};
use frame_system::EnsureRootWithSuccess;
use frame_system::{EnsureRoot, EnsureRootWithSuccess};
pub use origins::{
pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt,
EnsureFellowship, Fellows, Masters, Members, ToVoice,
};
use pallet_ranked_collective::EnsureOfRank;
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use parachains_common::{polkadot::account, HOURS};
use parachains_common::westend::{account, currency::GRAND};
use polkadot_runtime_common::impls::{
LocatableAssetConverter, VersionedLocatableAsset, VersionedMultiLocationConverter,
};
use sp_arithmetic::Permill;
use sp_core::{ConstU128, ConstU32};
use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst};
use sp_runtime::traits::{
AccountIdConversion, ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst,
};
use westend_runtime_constants::time::HOURS;
use xcm::prelude::*;
use xcm_builder::{AliasesIntoAccountId32, PayOverXcm};
#[cfg(feature = "runtime-benchmarks")]
use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure};
#[cfg(feature = "runtime-benchmarks")]
use parachains_common::westend::currency::DOLLARS;
/// The Fellowship members' ranks.
pub mod ranks {
@@ -191,8 +204,6 @@ impl pallet_core_fellowship::Config<FellowshipCoreInstance> for Runtime {
pub type FellowshipSalaryInstance = pallet_salary::Instance1;
use xcm::prelude::*;
parameter_types! {
// 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.
@@ -236,3 +247,102 @@ impl pallet_salary::Config<FellowshipSalaryInstance> for Runtime {
// Total monthly salary budget.
type Budget = ConstU128<{ 100_000 * USDT_UNITS }>;
}
parameter_types! {
pub const FellowshipTreasuryPalletId: PalletId = account::FELLOWSHIP_TREASURY_PALLET_ID;
pub const HundredPercent: Permill = Permill::from_percent(100);
pub const Burn: Permill = Permill::from_percent(0);
pub const MaxBalance: Balance = Balance::max_value();
// The asset's interior location for the paying account. This is the Fellowship Treasury
// pallet instance (which sits at index 65).
pub FellowshipTreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(65).into();
}
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
// Benchmark bond. Needed to make `propose_spend` work.
pub const TenPercent: Permill = Permill::from_percent(10);
// Benchmark minimum. Needed to make `propose_spend` work.
pub const BenchmarkProposalBondMinimum: Balance = 1 * DOLLARS;
// Benchmark maximum. Needed to make `propose_spend` work.
pub const BenchmarkProposalBondMaximum: Balance = 10 * DOLLARS;
}
/// [`PayOverXcm`] setup to pay the Fellowship Treasury.
pub type FellowshipTreasuryPaymaster = PayOverXcm<
FellowshipTreasuryInteriorLocation,
crate::xcm_config::XcmRouter,
crate::PolkadotXcm,
ConstU32<{ 6 * HOURS }>,
VersionedMultiLocation,
VersionedLocatableAsset,
LocatableAssetConverter,
VersionedMultiLocationConverter,
>;
pub type FellowshipTreasuryInstance = pallet_treasury::Instance1;
impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
// The creation of proposals via the treasury pallet is deprecated and should not be utilized.
// Instead, public or fellowship referenda should be used to propose and command the treasury
// spend or spend_local dispatchables. The parameters below have been configured accordingly to
// discourage its use.
// TODO: replace with `NeverEnsure` once polkadot-sdk 1.5 is released.
type ApproveOrigin = NeverEnsureOrigin<()>;
type OnSlash = ();
#[cfg(not(feature = "runtime-benchmarks"))]
type ProposalBond = HundredPercent;
#[cfg(not(feature = "runtime-benchmarks"))]
type ProposalBondMinimum = MaxBalance;
#[cfg(not(feature = "runtime-benchmarks"))]
type ProposalBondMaximum = MaxBalance;
#[cfg(feature = "runtime-benchmarks")]
type ProposalBond = TenPercent;
#[cfg(feature = "runtime-benchmarks")]
type ProposalBondMinimum = BenchmarkProposalBondMinimum;
#[cfg(feature = "runtime-benchmarks")]
type ProposalBondMaximum = BenchmarkProposalBondMaximum;
// end.
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
type PalletId = FellowshipTreasuryPalletId;
type Currency = Balances;
type RejectOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
EitherOfDiverse<EnsureXcm<IsVoiceOfBody<GovernanceLocation, TreasurerBodyId>>, Fellows>,
>;
type RuntimeEvent = RuntimeEvent;
type SpendPeriod = ConstU32<{ 7 * DAYS }>;
type Burn = Burn;
type BurnDestination = ();
type SpendFunds = ();
type MaxApprovals = ConstU32<100>;
type SpendOrigin = EitherOf<
EitherOf<
EnsureRootWithSuccess<AccountId, MaxBalance>,
MapSuccess<
EnsureXcm<IsVoiceOfBody<GovernanceLocation, TreasurerBodyId>>,
Replace<ConstU128<{ 10_000 * GRAND }>>,
>,
>,
EitherOf<
MapSuccess<Architects, Replace<ConstU128<{ 10_000 * GRAND }>>>,
MapSuccess<Fellows, Replace<ConstU128<{ 10 * GRAND }>>>,
>,
>;
type AssetKind = VersionedLocatableAsset;
type Beneficiary = VersionedMultiLocation;
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
#[cfg(not(feature = "runtime-benchmarks"))]
type Paymaster = FellowshipTreasuryPaymaster;
#[cfg(feature = "runtime-benchmarks")]
type Paymaster = PayWithEnsure<FellowshipTreasuryPaymaster, OpenHrmpChannel<ConstU32<1000>>>;
type BalanceConverter = AssetRate;
type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments<
sp_core::ConstU8<1>,
ConstU32<1000>,
>;
}