From 101882e69e089eed8f0ec2180427be76bac6f630 Mon Sep 17 00:00:00 2001 From: Muharem Date: Fri, 5 Jan 2024 16:49:14 +0800 Subject: [PATCH] Local Pluralities Get Free Xcm Execution (#125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Local Root and Pluralities Get Free Xcm Execution After running e2e tests, we discovered that xcm programs sent from local pluralities such as Relay Chain Staking Admin or Collectives Fellowship were failing due to insufficient balance to cover execution/delivery fees. This PR addresses this issue by granting them a free execution. Additionally, we encountered similar failures when attempting to teleport slashed assets from Collectives to the Relay Chain Treasury. In this PR, we resolve this problem by teleporting those assets on behalf of the Collectives root location, allowing for a free delivery. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- CHANGELOG.md | 1 + relay/kusama/src/xcm_config.rs | 12 +++++-- relay/polkadot/src/xcm_config.rs | 12 +++++-- .../src/fellowship/mod.rs | 18 +++++----- .../collectives-polkadot/src/impls.rs | 33 ++++++++++++------- .../collectives-polkadot/src/lib.rs | 8 ++--- .../collectives-polkadot/src/xcm_config.rs | 24 ++++++++++---- 7 files changed, 70 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 942c6dc292..7824f1e3e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Election provider: use a geometric deposit base calculation for EPM signed submissions in Polkadot and Kusama ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) - Make `IdentityInfo` generic in `pallet-identity` ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: https://github.com/paritytech/polkadot-sdk/pull/1661 - Whitelist `force_default_xcm_version` in XCM call filter ([polkadot-fellows/runtimes#45](https://github.com/polkadot-fellows/runtimes/pull/45)) +- Set up an account ID for the local root location on Polkadot Collectives ([polkadot-fellows/runtimes#125](https://github.com/polkadot-fellows/runtimes/pull/125)) - Increase confirmation period for treasury spend tracks on Polkadot & Kusama ([polkadot-fellows/runtimes#119](https://github.com/polkadot-fellows/runtimes/pull/119)) ### Added diff --git a/relay/kusama/src/xcm_config.rs b/relay/kusama/src/xcm_config.rs index 4e9798a122..75eb39ab69 100644 --- a/relay/kusama/src/xcm_config.rs +++ b/relay/kusama/src/xcm_config.rs @@ -23,7 +23,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Contains, Equals, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -47,6 +47,7 @@ use xcm_builder::{ use xcm_executor::traits::WithOriginFilter; parameter_types! { + pub const RootLocation: MultiLocation = Here.into_location(); /// The location of the KSM token, from the context of this chain. Since this token is native to this /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to /// the context". @@ -147,6 +148,9 @@ match_types! { pub type OnlyParachains: impl Contains = { MultiLocation { parents: 0, interior: X1(Parachain(_)) } }; + pub type LocalPlurality: impl Contains = { + MultiLocation { parents: 0, interior: X1(Plurality { .. }) } + }; } /// The barriers one of which must be passed for an XCM message to be executed. @@ -321,6 +325,10 @@ impl Contains for SafeCallFilter { } } +/// Locations that will not be charged fees in the executor, neither for execution nor delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = (SystemParachains, Equals, LocalPlurality); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -347,7 +355,7 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeesToAccount; // No bridges yet... type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/relay/polkadot/src/xcm_config.rs b/relay/polkadot/src/xcm_config.rs index 65c0348fe1..e019879b36 100644 --- a/relay/polkadot/src/xcm_config.rs +++ b/relay/polkadot/src/xcm_config.rs @@ -23,7 +23,7 @@ use super::{ }; use frame_support::{ match_types, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Contains, Equals, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -52,6 +52,7 @@ use xcm_builder::{ use xcm_executor::traits::WithOriginFilter; parameter_types! { + pub const RootLocation: MultiLocation = Here.into_location(); /// The location of the DOT token, from the context of this chain. Since this token is native to this /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to /// the context". @@ -161,6 +162,9 @@ match_types! { MultiLocation { parents: 0, interior: X1(Parachain(COLLECTIVES_ID)) } | MultiLocation { parents: 0, interior: X2(Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }) } }; + pub type LocalPlurality: impl Contains = { + MultiLocation { parents: 0, interior: X1(Plurality { .. }) } + }; } /// The barriers one of which must be passed for an XCM message to be executed. @@ -324,6 +328,10 @@ impl Contains for SafeCallFilter { } } +/// Locations that will not be charged fees in the executor, neither for execution nor delivery. +/// We only waive fees for system functions, which these locations represent. +pub type WaivedLocations = (SystemParachains, Equals, LocalPlurality); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -351,7 +359,7 @@ impl xcm_executor::Config for XcmConfig { type SubscriptionService = XcmPallet; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type FeeManager = XcmFeesToAccount; + type FeeManager = XcmFeesToAccount; // No bridges yet... type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs b/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs index 8a5885e476..fe7ade4a12 100644 --- a/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/system-parachains/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -19,9 +19,12 @@ mod origins; mod tracks; use crate::{ - impls::ToParentTreasury, weights, xcm_config::TreasurerBodyId, AccountId, AssetRate, Balance, - Balances, FellowshipReferenda, GovernanceLocation, PolkadotTreasuryAccount, Preimage, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, DAYS, + impls::ToParentTreasury, + weights, + xcm_config::{LocationToAccountId, TreasurerBodyId}, + AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, + PolkadotTreasuryAccount, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + Scheduler, DAYS, }; use cumulus_primitives_core::Junction::GeneralIndex; use frame_support::{ @@ -44,10 +47,7 @@ use polkadot_runtime_common::impls::{ use polkadot_runtime_constants::{currency::GRAND, time::HOURS, xcm::body::FELLOWSHIP_ADMIN_INDEX}; use sp_arithmetic::Permill; use sp_core::{ConstU128, ConstU32}; -use sp_runtime::traits::{ - AccountIdConversion, ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst, -}; -use system_parachains_constants::polkadot::account; +use sp_runtime::traits::{ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst}; use xcm::latest::BodyId; use xcm_builder::{AliasesIntoAccountId32, LocatableAssetId, PayOverXcm}; @@ -70,8 +70,6 @@ pub mod ranks { } parameter_types! { - // Referenda pallet account, used to temporarily deposit slashed imbalance before teleporting. - pub ReferendaPalletAccount: AccountId = account::REFERENDA_PALLET_ID.into_account_truncating(); pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); } @@ -101,7 +99,7 @@ impl pallet_referenda::Config for Runtime { >; type CancelOrigin = Architects; type KillOrigin = Masters; - type Slash = ToParentTreasury; + type Slash = ToParentTreasury; type Votes = pallet_ranked_collective::Votes; type Tally = pallet_ranked_collective::TallyOf; type SubmissionDeposit = ConstU128<0>; diff --git a/system-parachains/collectives/collectives-polkadot/src/impls.rs b/system-parachains/collectives/collectives-polkadot/src/impls.rs index fb2feb63ec..a59c181db6 100644 --- a/system-parachains/collectives/collectives-polkadot/src/impls.rs +++ b/system-parachains/collectives/collectives-polkadot/src/impls.rs @@ -24,7 +24,8 @@ use pallet_alliance::{ProposalIndex, ProposalProvider}; use parachains_common::impls::NegativeImbalance; use sp_runtime::DispatchError; use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; -use xcm::latest::{Fungibility, Junction, Parent, WeightLimit}; +use xcm::latest::{Fungibility, Junction, Junctions::Here, MultiLocation, Parent, WeightLimit}; +use xcm_executor::traits::ConvertLocation; type AccountIdOf = ::AccountId; @@ -38,19 +39,19 @@ pub type BalanceOf = /// Implements `OnUnbalanced::on_unbalanced` to teleport slashed assets to relay chain treasury /// account. -pub struct ToParentTreasury( - PhantomData<(TreasuryAccount, PalletAccount, T)>, +pub struct ToParentTreasury( + PhantomData<(TreasuryAccount, AccountIdConverter, T)>, ); -impl OnUnbalanced> - for ToParentTreasury +impl OnUnbalanced> + for ToParentTreasury where T: pallet_balances::Config + pallet_xcm::Config + frame_system::Config, <::RuntimeOrigin as OriginTrait>::AccountId: From>, [u8; 32]: From<::AccountId>, TreasuryAccount: Get>, - PalletAccount: Get>, BalanceOf: Into, + AccountIdConverter: ConvertLocation>, { fn on_unbalanced(amount: NegativeImbalance) { let amount = match amount.drop_zero() { @@ -58,16 +59,24 @@ where Err(amount) => amount, }; let imbalance = amount.peek(); - let pallet_acc: AccountIdOf = PalletAccount::get(); - let treasury_acc: AccountIdOf = TreasuryAccount::get(); - - >::resolve_creating(&pallet_acc, amount); + let root_location: MultiLocation = Here.into(); + let root_account: AccountIdOf = + match AccountIdConverter::convert_location(&root_location) { + Some(a) => a, + None => { + log::warn!("Failed to convert root origin into account id"); + return + }, + }; + let treasury_account: AccountIdOf = TreasuryAccount::get(); + + >::resolve_creating(&root_account, amount); let result = >::limited_teleport_assets( - <::RuntimeOrigin>::signed(pallet_acc.into()), + <::RuntimeOrigin>::root(), Box::new(Parent.into()), Box::new( - Junction::AccountId32 { network: None, id: treasury_acc.into() } + Junction::AccountId32 { network: None, id: treasury_account.into() } .into_location() .into(), ), diff --git a/system-parachains/collectives/collectives-polkadot/src/lib.rs b/system-parachains/collectives/collectives-polkadot/src/lib.rs index 1a0e82c052..4e3d34d9eb 100644 --- a/system-parachains/collectives/collectives-polkadot/src/lib.rs +++ b/system-parachains/collectives/collectives-polkadot/src/lib.rs @@ -87,7 +87,8 @@ use system_parachains_constants::{ SLOT_DURATION, }; use xcm_config::{ - GovernanceLocation, TreasurerBodyId, XcmConfig, XcmOriginToTransactDispatchOrigin, + GovernanceLocation, LocationToAccountId, TreasurerBodyId, XcmConfig, + XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -509,9 +510,6 @@ pub const MAX_ALLIES: u32 = 100; parameter_types! { pub const AllyDeposit: Balance = 1_000 * UNITS; // 1,000 DOT bond to join as an Ally - // The Alliance pallet account, used as a temporary place to deposit a slashed imbalance - // before the teleport to the Treasury. - pub AlliancePalletAccount: AccountId = ALLIANCE_PALLET_ID.into_account_truncating(); pub PolkadotTreasuryAccount: AccountId = POLKADOT_TREASURY_PALLET_ID.into_account_truncating(); // The number of blocks a member must wait between giving a retirement notice and retiring. // Supposed to be greater than time required to `kick_member` with alliance motion. @@ -525,7 +523,7 @@ impl pallet_alliance::Config for Runtime { type MembershipManager = RootOrAllianceTwoThirdsMajority; type AnnouncementOrigin = RootOrAllianceTwoThirdsMajority; type Currency = Balances; - type Slashed = ToParentTreasury; + type Slashed = ToParentTreasury; type InitializeMembers = AllianceMotion; type MembershipChanged = AllianceMotion; type RetirementPeriod = AllianceRetirementPeriod; diff --git a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs index 0047b40aec..c336764488 100644 --- a/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs +++ b/system-parachains/collectives/collectives-polkadot/src/xcm_config.rs @@ -38,15 +38,16 @@ use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, - EnsureXcmOrigin, FixedWeightBounds, HashedDescription, IsConcrete, OriginToPluralityVoice, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, + DescribeTerminus, EnsureXcmOrigin, FixedWeightBounds, HashedDescription, IsConcrete, + OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; parameter_types! { + pub const RootLocation: MultiLocation = MultiLocation::here(); pub const DotLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Polkadot); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); @@ -71,6 +72,8 @@ pub type LocationToAccountId = ( AccountId32Aliases, // Foreign locations alias into accounts according to a hash of their standard description. HashedDescription>, + // Here/local root location to `AccountId`. + HashedDescription, ); /// Means for transacting the native currency on this chain. @@ -132,6 +135,9 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(_) } }; + pub type LocalPlurality: impl Contains = { + MultiLocation { parents: 0, interior: X1(Plurality { .. }) } + }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -261,8 +267,12 @@ match_types! { /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, + Equals, + LocalPlurality, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - DOT with the parent Relay Chain and sibling parachains.