From dd46523f827eb3a4a2a290515de030da34b21f0f Mon Sep 17 00:00:00 2001
From: Muharem Ismailov <ismailov.m.h@gmail.com>
Date: Wed, 21 Dec 2022 09:33:01 +0100
Subject: [PATCH] Kusama origins as xcm multi_location (#6273)

* Kusamsa origins as xcm multilocation

* Fellows origin index

* origins to xcm plurality body

* cleanup

* fix cargo spellcheck

* Apply suggestions from code review

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* include Fellows into scope

* include Fellows into scope

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: Gavin Wood <gavin@parity.io>
---
 polkadot/runtime/kusama/src/lib.rs            |  2 +-
 polkadot/runtime/kusama/src/xcm_config.rs     | 42 +++++++++++++++----
 polkadot/xcm/pallet-xcm/src/lib.rs            | 13 ++++++
 polkadot/xcm/src/v0/junction.rs               |  9 ++++
 polkadot/xcm/xcm-builder/src/lib.rs           |  2 +-
 .../xcm/xcm-builder/src/origin_conversion.rs  | 17 ++++++++
 6 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs
index a67e2d46735..125ce049b19 100644
--- a/polkadot/runtime/kusama/src/lib.rs
+++ b/polkadot/runtime/kusama/src/lib.rs
@@ -106,7 +106,7 @@ pub mod xcm_config;
 // Governance configurations.
 pub mod governance;
 use governance::{
-	old::CouncilCollective, pallet_custom_origins, AuctionAdmin, GeneralAdmin, LeaseAdmin,
+	old::CouncilCollective, pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin,
 	StakingAdmin, Treasurer, TreasurySpender,
 };
 use xcm_config::CheckAccount;
diff --git a/polkadot/runtime/kusama/src/xcm_config.rs b/polkadot/runtime/kusama/src/xcm_config.rs
index 17310dd5ead..55a474e239f 100644
--- a/polkadot/runtime/kusama/src/xcm_config.rs
+++ b/polkadot/runtime/kusama/src/xcm_config.rs
@@ -17,8 +17,8 @@
 //! XCM configurations for the Kusama runtime.
 
 use super::{
-	parachains_origin, AccountId, Balances, CouncilCollective, ParaId, Runtime, RuntimeCall,
-	RuntimeEvent, RuntimeOrigin, WeightToFee, XcmPallet,
+	parachains_origin, AccountId, Balances, CouncilCollective, Fellows, ParaId, Runtime,
+	RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, WeightToFee, XcmPallet,
 };
 use frame_support::{match_types, parameter_types, traits::Everything};
 use runtime_common::{xcm_sender, ToAuthor};
@@ -28,8 +28,8 @@ use xcm_builder::{
 	AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, BackingToPlurality,
 	ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
 	CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
-	LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
-	TakeWeightCredit, UsingComponents, WeightInfoBounds,
+	LocationInverter, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
+	SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
 };
 
 parameter_types! {
@@ -154,6 +154,10 @@ impl xcm_executor::Config for XcmConfig {
 
 parameter_types! {
 	pub const CouncilBodyId: BodyId = BodyId::Executive;
+	// StakingAdmin pluralistic body.
+	pub const StakingAdminBodyId: BodyId = BodyId::Defense;
+	// Fellows pluralistic body.
+	pub const FellowsBodyId: BodyId = BodyId::Technical;
 }
 
 /// Type to convert the council origin to a Plurality `MultiLocation` value.
@@ -172,13 +176,33 @@ pub type LocalOriginToLocation = (
 	// And a usual Signed origin to be used in XCM as a corresponding AccountId32
 	SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>,
 );
+
+/// Type to convert the `StakingAdmin` origin to a Plurality `MultiLocation` value.
+pub type StakingAdminToPlurality =
+	OriginToPluralityVoice<RuntimeOrigin, StakingAdmin, StakingAdminBodyId>;
+
+/// Type to convert the Fellows origin to a Plurality `MultiLocation` value.
+pub type FellowsToPlurality = OriginToPluralityVoice<RuntimeOrigin, Fellows, FellowsBodyId>;
+
+/// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an interior location
+/// of this chain for a destination chain.
+pub type LocalPalletOriginToLocation = (
+	// We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality of the
+	// `Unit` body.
+	CouncilToPlurality,
+	// StakingAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
+	StakingAdminToPlurality,
+	// Fellows origin to be used in XCM as a corresponding Plurality `MultiLocation` value.
+	FellowsToPlurality,
+);
+
 impl pallet_xcm::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
-	// We only allow the council to send messages. This is basically safe to enable for everyone
-	// (safe the possibility of someone spamming the parachain if they're willing to pay the KSM to
-	// send from the Relay-chain), but it's useless until we bring in XCM v3 which will make
-	// `DescendOrigin` a bit more useful.
-	type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, CouncilToPlurality>;
+	// We only allow the root, the council, fellows and the staking admin to send messages.
+	// This is basically safe to enable for everyone (safe the possibility of someone spamming the parachain
+	// if they're willing to pay the KSM to send from the Relay-chain), but it's useless until we bring in XCM v3
+	// which will make `DescendOrigin` a bit more useful.
+	type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalPalletOriginToLocation>;
 	type XcmRouter = XcmRouter;
 	// Anyone can execute XCM messages locally.
 	type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs
index f645e3cfc86..3502c79b5d2 100644
--- a/polkadot/xcm/pallet-xcm/src/lib.rs
+++ b/polkadot/xcm/pallet-xcm/src/lib.rs
@@ -1527,6 +1527,19 @@ impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Contains<MultiLocation>
 	}
 }
 
+/// Filter for `MultiLocation` to find those which represent a voice of an identified plurality.
+///
+/// May reasonably be used with `EnsureXcm`.
+pub struct IsVoiceOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>);
+impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Contains<MultiLocation>
+	for IsVoiceOfBody<Prefix, Body>
+{
+	fn contains(l: &MultiLocation) -> bool {
+		let maybe_suffix = l.match_and_split(&Prefix::get());
+		matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part == &BodyPart::Voice)
+	}
+}
+
 /// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognize and filter the
 /// `Origin::Xcm` item.
 pub struct EnsureXcm<F>(PhantomData<F>);
diff --git a/polkadot/xcm/src/v0/junction.rs b/polkadot/xcm/src/v0/junction.rs
index 67f17f464a3..450e882ac3e 100644
--- a/polkadot/xcm/src/v0/junction.rs
+++ b/polkadot/xcm/src/v0/junction.rs
@@ -52,6 +52,15 @@ pub enum BodyId {
 	/// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it
 	/// may be considered as that).
 	Judicial,
+	/// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public referendum
+	/// on the `staking_admin` track).
+	Defense,
+	/// The unambiguous administration body (for Polkadot, an opinion on the topic given via a public referendum
+	/// on the `general_admin` track).
+	Administration,
+	/// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public referendum
+	/// on the `treasurer` track).
+	Treasury,
 }
 
 /// A part of a pluralistic body.
diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs
index e3473d55d5e..aa55c56d2cd 100644
--- a/polkadot/xcm/xcm-builder/src/lib.rs
+++ b/polkadot/xcm/xcm-builder/src/lib.rs
@@ -37,7 +37,7 @@ pub use location_conversion::{
 mod origin_conversion;
 pub use origin_conversion::{
 	BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin,
-	ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
+	OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
 	SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative,
 	SignedToAccountId32, SovereignSignedViaLocation,
 };
diff --git a/polkadot/xcm/xcm-builder/src/origin_conversion.rs b/polkadot/xcm/xcm-builder/src/origin_conversion.rs
index 9fe50eaf9c3..4d024a9d12c 100644
--- a/polkadot/xcm/xcm-builder/src/origin_conversion.rs
+++ b/polkadot/xcm/xcm-builder/src/origin_conversion.rs
@@ -321,3 +321,20 @@ where
 		})
 	}
 }
+
+/// `Convert` implementation to convert from an origin which passes the check of an `EnsureOrigin`
+/// into a voice of a given pluralistic `Body`.
+pub struct OriginToPluralityVoice<RuntimeOrigin, EnsureBodyOrigin, Body>(
+	PhantomData<(RuntimeOrigin, EnsureBodyOrigin, Body)>,
+);
+impl<RuntimeOrigin: Clone, EnsureBodyOrigin: EnsureOrigin<RuntimeOrigin>, Body: Get<BodyId>>
+	Convert<RuntimeOrigin, MultiLocation>
+	for OriginToPluralityVoice<RuntimeOrigin, EnsureBodyOrigin, Body>
+{
+	fn convert(o: RuntimeOrigin) -> Result<MultiLocation, RuntimeOrigin> {
+		match EnsureBodyOrigin::try_origin(o) {
+			Ok(_) => Ok(Junction::Plurality { id: Body::get(), part: BodyPart::Voice }.into()),
+			Err(o) => Err(o),
+		}
+	}
+}
-- 
GitLab