Skip to content

Commit 49a04e5

Browse files
muharembkchrjoepetrowskiggwpez
authored
Fellowship Treasury (#109)
Treasury Pallet Instance for the Fellowship in Polkadot 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. test with xcm-emulator for the same setup in Westend - paritytech/polkadot-sdk#2532 more details on new treasury features and asset rate pallet - paritytech/polkadot-sdk#1333 --------- Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: joepetrowski <[email protected]> Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Oliver Tale-Yazdi <[email protected]>
1 parent d67b905 commit 49a04e5

File tree

12 files changed

+515
-20
lines changed

12 files changed

+515
-20
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2222
- XCM transport fees are now exponential and are sent to a treasury account ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: https://github.com/paritytech/polkadot-sdk/pull/1234
2323
- System parachains are now trusted teleporters of each other ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: https://github.com/paritytech/polkadot-sdk/pull/1368
2424
- Treasury is able to spend various asset kinds ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87))
25+
- Fellowship Treasury pallet on Polkadot Collectives ([polkadot-fellows/runtimes#109](https://github.com/polkadot-fellows/runtimes/pull/109))
2526

2627
### Fixed
2728

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

relay/polkadot/constants/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ pub mod xcm {
108108
const ROOT_INDEX: u32 = 0;
109109
// The bodies corresponding to the Polkadot OpenGov Origins.
110110
pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1;
111+
// The body corresponding to the Treasurer OpenGov track.
112+
pub const TREASURER_INDEX: u32 = 2;
111113
}
112114
}
113115

relay/polkadot/src/xcm_config.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use super::{
2020
parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin,
2121
GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin,
22-
TransactionByteFee, Treasury, WeightToFee, XcmPallet,
22+
TransactionByteFee, Treasurer, Treasury, WeightToFee, XcmPallet,
2323
};
2424
use frame_support::{
2525
match_types, parameter_types,
@@ -29,7 +29,9 @@ use frame_support::{
2929
use frame_system::EnsureRoot;
3030
use pallet_xcm::XcmPassthrough;
3131
use polkadot_runtime_constants::{
32-
currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX,
32+
currency::CENTS,
33+
system_parachain::*,
34+
xcm::body::{FELLOWSHIP_ADMIN_INDEX, TREASURER_INDEX},
3335
};
3436
use runtime_common::{
3537
crowdloan, paras_registrar,
@@ -362,6 +364,8 @@ parameter_types! {
362364
pub const StakingAdminBodyId: BodyId = BodyId::Defense;
363365
// FellowshipAdmin pluralistic body.
364366
pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
367+
// `Treasurer` pluralistic body.
368+
pub const TreasurerBodyId: BodyId = BodyId::Index(TREASURER_INDEX);
365369
}
366370

367371
#[cfg(feature = "runtime-benchmarks")]
@@ -389,6 +393,9 @@ pub type StakingAdminToPlurality =
389393
pub type FellowshipAdminToPlurality =
390394
OriginToPluralityVoice<RuntimeOrigin, FellowshipAdmin, FellowshipAdminBodyId>;
391395

396+
/// Type to convert the `Treasurer` origin to a Plurality `MultiLocation` value.
397+
pub type TreasurerToPlurality = OriginToPluralityVoice<RuntimeOrigin, Treasurer, TreasurerBodyId>;
398+
392399
/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an
393400
/// interior location of this chain for a destination chain.
394401
pub type LocalPalletOriginToLocation = (
@@ -398,6 +405,8 @@ pub type LocalPalletOriginToLocation = (
398405
StakingAdminToPlurality,
399406
// FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
400407
FellowshipAdminToPlurality,
408+
// `Treasurer` origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
409+
TreasurerToPlurality,
401410
);
402411

403412
impl pallet_xcm::Config for Runtime {

system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,13 @@ match_types! {
189189
MultiLocation { parents: 1, interior: Here } |
190190
MultiLocation { parents: 1, interior: X1(_) }
191191
};
192-
pub type FellowsPlurality: impl Contains<MultiLocation> = {
193-
MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) }
194-
};
195-
pub type FellowshipSalaryPallet: impl Contains<MultiLocation> = {
196-
MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(64)) }
192+
pub type FellowshipEntities: impl Contains<MultiLocation> = {
193+
// Fellowship Plurality
194+
MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) } |
195+
// Fellowship Salary Pallet
196+
MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(64)) } |
197+
// Fellowship Treasury Pallet
198+
MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(65)) }
197199
};
198200
}
199201

@@ -380,8 +382,7 @@ pub type Barrier = TrailingSetTopicAsId<
380382
// The locations listed below get free execution.
381383
AllowExplicitUnpaidExecutionFrom<(
382384
ParentOrParentsPlurality,
383-
FellowsPlurality,
384-
FellowshipSalaryPallet,
385+
FellowshipEntities,
385386
Equals<RelayTreasuryLocation>,
386387
)>,
387388
// Subscriptions for version tracking are OK.
@@ -419,8 +420,7 @@ match_types! {
419420
pub type WaivedLocations = (
420421
RelayOrOtherSystemParachains<SystemParachains, Runtime>,
421422
Equals<RelayTreasuryLocation>,
422-
FellowsPlurality,
423-
FellowshipSalaryPallet,
423+
FellowshipEntities,
424424
);
425425

426426
/// Cases where a remote origin is accepted as trusted Teleporter for a given asset:

system-parachains/collectives/collectives-polkadot/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ frame-system = { default-features = false, version = "25.0.0" }
2323
frame-system-benchmarking = { default-features = false, optional = true, version = "25.0.0" }
2424
frame-system-rpc-runtime-api = { default-features = false, version = "23.0.0" }
2525
frame-try-runtime = { default-features = false, optional = true, version = "0.31.0" }
26+
pallet-asset-rate = { default-features = false , version = "4.0.0" }
2627
pallet-alliance = { default-features = false, version = "24.0.0" }
2728
pallet-aura = { default-features = false, version = "24.0.0" }
2829
pallet-authorship = { default-features = false, version = "25.0.0" }
@@ -36,6 +37,7 @@ pallet-session = { default-features = false, version = "25.0.0" }
3637
pallet-timestamp = { default-features = false, version = "24.0.0" }
3738
pallet-transaction-payment = { default-features = false, version = "25.0.0" }
3839
pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = "25.0.0" }
40+
pallet-treasury = { default-features = false , version = "24.0.0" }
3941
pallet-utility = { default-features = false, version = "25.0.0" }
4042
pallet-referenda = { default-features = false, version = "25.0.0" }
4143
pallet-ranked-collective = { default-features = false, version = "25.0.0" }
@@ -92,6 +94,7 @@ runtime-benchmarks = [
9294
"frame-support/runtime-benchmarks",
9395
"frame-system-benchmarking/runtime-benchmarks",
9496
"frame-system/runtime-benchmarks",
97+
"pallet-asset-rate/runtime-benchmarks",
9598
"pallet-alliance/runtime-benchmarks",
9699
"pallet-balances/runtime-benchmarks",
97100
"pallet-collator-selection/runtime-benchmarks",
@@ -105,6 +108,7 @@ runtime-benchmarks = [
105108
"pallet-salary/runtime-benchmarks",
106109
"pallet-scheduler/runtime-benchmarks",
107110
"pallet-timestamp/runtime-benchmarks",
111+
"pallet-treasury/runtime-benchmarks",
108112
"pallet-utility/runtime-benchmarks",
109113
"pallet-xcm/runtime-benchmarks",
110114
"polkadot-parachain-primitives/runtime-benchmarks",
@@ -123,6 +127,7 @@ try-runtime = [
123127
"frame-support/try-runtime",
124128
"frame-system/try-runtime",
125129
"frame-try-runtime/try-runtime",
130+
"pallet-asset-rate/try-runtime",
126131
"pallet-alliance/try-runtime",
127132
"pallet-aura/try-runtime",
128133
"pallet-authorship/try-runtime",
@@ -140,6 +145,7 @@ try-runtime = [
140145
"pallet-session/try-runtime",
141146
"pallet-timestamp/try-runtime",
142147
"pallet-transaction-payment/try-runtime",
148+
"pallet-treasury/try-runtime",
143149
"pallet-utility/try-runtime",
144150
"pallet-xcm/try-runtime",
145151
"parachain-info/try-runtime",
@@ -164,6 +170,7 @@ std = [
164170
"frame-system/std",
165171
"frame-try-runtime?/std",
166172
"log/std",
173+
"pallet-asset-rate/std",
167174
"pallet-alliance/std",
168175
"pallet-aura/std",
169176
"pallet-authorship/std",
@@ -182,6 +189,7 @@ std = [
182189
"pallet-timestamp/std",
183190
"pallet-transaction-payment-rpc-runtime-api/std",
184191
"pallet-transaction-payment/std",
192+
"pallet-treasury/std",
185193
"pallet-utility/std",
186194
"pallet-xcm/std",
187195
"parachain-info/std",

system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs

+137-7
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,35 @@
1919
mod origins;
2020
mod tracks;
2121
use crate::{
22-
impls::ToParentTreasury, weights, AccountId, Balance, Balances, FellowshipReferenda,
23-
GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent,
24-
RuntimeOrigin, Scheduler, DAYS,
22+
impls::ToParentTreasury, weights, xcm_config::TreasurerBodyId, AccountId, AssetRate, Balance,
23+
Balances, FellowshipReferenda, GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime,
24+
RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, DAYS,
2525
};
2626
use cumulus_primitives_core::Junction::GeneralIndex;
2727
use frame_support::{
2828
parameter_types,
29-
traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg},
29+
traits::{
30+
EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, PalletInfoAccess, TryWithMorphedArg,
31+
},
32+
PalletId,
3033
};
31-
use frame_system::EnsureRootWithSuccess;
34+
use frame_system::{EnsureRoot, EnsureRootWithSuccess};
3235
pub use origins::{
3336
pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt,
3437
EnsureFellowship, Fellows, Masters, Members, ToVoice,
3538
};
3639
use pallet_ranked_collective::EnsureOfRank;
3740
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
3841
use parachains_common::polkadot::account;
39-
use polkadot_runtime_constants::{time::HOURS, xcm::body::FELLOWSHIP_ADMIN_INDEX};
42+
use polkadot_runtime_common::impls::{
43+
LocatableAssetConverter, VersionedLocatableAsset, VersionedMultiLocationConverter,
44+
};
45+
use polkadot_runtime_constants::{currency::GRAND, time::HOURS, xcm::body::FELLOWSHIP_ADMIN_INDEX};
46+
use sp_arithmetic::Permill;
4047
use sp_core::{ConstU128, ConstU32};
41-
use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst};
48+
use sp_runtime::traits::{
49+
AccountIdConversion, ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst,
50+
};
4251
use xcm::latest::BodyId;
4352
use xcm_builder::{AliasesIntoAccountId32, LocatableAssetId, PayOverXcm};
4453

@@ -244,3 +253,124 @@ impl pallet_salary::Config<FellowshipSalaryInstance> for Runtime {
244253
// Total monthly salary budget.
245254
type Budget = ConstU128<{ 100_000 * USDT_UNITS }>;
246255
}
256+
257+
parameter_types! {
258+
// TODO: reference the constant value from common crate when polkadot-sdk 1.5 is released.
259+
// https://github.com/polkadot-fellows/runtimes/issues/113
260+
pub const FellowshipTreasuryPalletId: PalletId = PalletId(*b"py/feltr");
261+
pub const ProposalBond: Permill = Permill::from_percent(100);
262+
pub const Burn: Permill = Permill::from_percent(0);
263+
pub const MaxBalance: Balance = Balance::max_value();
264+
// The asset's interior location for the paying account. This is the Fellowship Treasury
265+
// pallet instance (which sits at index 65).
266+
pub FellowshipTreasuryInteriorLocation: InteriorMultiLocation =
267+
PalletInstance(<crate::FellowshipTreasury as PalletInfoAccess>::index() as u8).into();
268+
}
269+
270+
/// [`PayOverXcm`] setup to pay the Fellowship Treasury.
271+
pub type FellowshipTreasuryPaymaster = PayOverXcm<
272+
FellowshipTreasuryInteriorLocation,
273+
crate::xcm_config::XcmRouter,
274+
crate::PolkadotXcm,
275+
ConstU32<{ 6 * HOURS }>,
276+
VersionedMultiLocation,
277+
VersionedLocatableAsset,
278+
LocatableAssetConverter,
279+
VersionedMultiLocationConverter,
280+
>;
281+
282+
pub type FellowshipTreasuryInstance = pallet_treasury::Instance1;
283+
284+
impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
285+
// The creation of proposals via the treasury pallet is deprecated and should not be utilized.
286+
// Instead, public or fellowship referenda should be used to propose and command the treasury
287+
// spend or spend_local dispatchables. The parameters below have been configured accordingly to
288+
// discourage its use.
289+
// TODO: replace with `NeverEnsure` once polkadot-sdk 1.5 is released.
290+
// https://github.com/polkadot-fellows/runtimes/issues/113
291+
type ApproveOrigin = EnsureRoot<AccountId>;
292+
type OnSlash = ();
293+
type ProposalBond = ProposalBond;
294+
type ProposalBondMinimum = MaxBalance;
295+
type ProposalBondMaximum = MaxBalance;
296+
// end.
297+
298+
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
299+
type RuntimeEvent = RuntimeEvent;
300+
type PalletId = FellowshipTreasuryPalletId;
301+
type Currency = Balances;
302+
type RejectOrigin = EitherOfDiverse<
303+
EnsureRoot<AccountId>,
304+
EitherOfDiverse<EnsureXcm<IsVoiceOfBody<GovernanceLocation, TreasurerBodyId>>, Fellows>,
305+
>;
306+
type SpendPeriod = ConstU32<{ 7 * DAYS }>;
307+
type Burn = Burn;
308+
type BurnDestination = ();
309+
type SpendFunds = ();
310+
type MaxApprovals = ConstU32<100>;
311+
type SpendOrigin = EitherOf<
312+
EitherOf<
313+
EnsureRootWithSuccess<AccountId, MaxBalance>,
314+
MapSuccess<
315+
EnsureXcm<IsVoiceOfBody<GovernanceLocation, TreasurerBodyId>>,
316+
Replace<ConstU128<{ 10_000 * GRAND }>>,
317+
>,
318+
>,
319+
EitherOf<
320+
MapSuccess<Architects, Replace<ConstU128<{ 10_000 * GRAND }>>>,
321+
MapSuccess<Fellows, Replace<ConstU128<{ 10 * GRAND }>>>,
322+
>,
323+
>;
324+
type AssetKind = VersionedLocatableAsset;
325+
type Beneficiary = VersionedMultiLocation;
326+
type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
327+
#[cfg(not(feature = "runtime-benchmarks"))]
328+
type Paymaster = FellowshipTreasuryPaymaster;
329+
#[cfg(feature = "runtime-benchmarks")]
330+
type Paymaster = PayWithEnsure<FellowshipTreasuryPaymaster, OpenHrmpChannel<ConstU32<1000>>>;
331+
type BalanceConverter = AssetRate;
332+
type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
333+
#[cfg(feature = "runtime-benchmarks")]
334+
type BenchmarkHelper = benchmarks::TreasuryArguments<sp_core::ConstU8<1>, ConstU32<1000>>;
335+
}
336+
337+
// TODO: replace by [`polkadot_runtime_common::impls::benchmarks::TreasuryArguments`] when
338+
// polkadot-sdk 1.5 is released.
339+
// https://github.com/polkadot-fellows/runtimes/issues/113
340+
#[cfg(feature = "runtime-benchmarks")]
341+
mod benchmarks {
342+
use super::VersionedLocatableAsset;
343+
use core::marker::PhantomData;
344+
use frame_support::traits::Get;
345+
use pallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory;
346+
use sp_core::{ConstU32, ConstU8};
347+
use xcm::prelude::*;
348+
349+
/// Provide factory methods for the [`VersionedLocatableAsset`] and the `Beneficiary` of the
350+
/// [`VersionedMultiLocation`]. The location of the asset is determined as a Parachain with an
351+
/// ID equal to the passed seed.
352+
pub struct TreasuryArguments<Parents = ConstU8<0>, ParaId = ConstU32<0>>(
353+
PhantomData<(Parents, ParaId)>,
354+
);
355+
impl<Parents: Get<u8>, ParaId: Get<u32>>
356+
TreasuryArgumentsFactory<VersionedLocatableAsset, VersionedMultiLocation>
357+
for TreasuryArguments<Parents, ParaId>
358+
{
359+
fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
360+
VersionedLocatableAsset::V3 {
361+
location: xcm::v3::MultiLocation::new(Parents::get(), X1(Parachain(ParaId::get()))),
362+
asset_id: xcm::v3::MultiLocation::new(
363+
0,
364+
X2(PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())),
365+
)
366+
.into(),
367+
}
368+
}
369+
fn create_beneficiary(seed: [u8; 32]) -> VersionedMultiLocation {
370+
VersionedMultiLocation::V3(xcm::v3::MultiLocation::new(
371+
0,
372+
X1(AccountId32 { network: None, id: seed }),
373+
))
374+
}
375+
}
376+
}

0 commit comments

Comments
 (0)