From f8a310fac74f14d01cfefe2ed7dfc94dadefa41d Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 21 Mar 2023 17:51:43 +0000 Subject: [PATCH 1/2] FeeManager that puts fees in a central account --- parachains/common/src/lib.rs | 8 +++- .../assets/statemine/src/xcm_config.rs | 8 +++- .../assets/statemint/src/xcm_config.rs | 8 +++- .../assets/westmint/src/xcm_config.rs | 8 +++- .../bridge-hub-kusama/src/xcm_config.rs | 11 +++-- .../bridge-hub-polkadot/src/xcm_config.rs | 11 +++-- .../bridge-hub-rococo/src/xcm_config.rs | 11 +++-- .../collectives-polkadot/src/xcm_config.rs | 7 +++- primitives/utility/src/lib.rs | 41 ++++++++++++++++++- 9 files changed, 94 insertions(+), 19 deletions(-) diff --git a/parachains/common/src/lib.rs b/parachains/common/src/lib.rs index 8ac464ea077..fcd1f5b749a 100644 --- a/parachains/common/src/lib.rs +++ b/parachains/common/src/lib.rs @@ -68,7 +68,10 @@ mod types { /// Common constants of parachains. mod constants { use super::types::BlockNumber; - use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}; + use frame_support::{ + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + PalletId, + }; use sp_runtime::Perbill; /// This determines the average expected block time that we are targeting. Blocks will be /// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by @@ -96,6 +99,9 @@ mod constants { WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), polkadot_primitives::MAX_POV_SIZE as u64, ); + + /// Relay Chain treasury pallet id, used to convert into AccountId + pub const RELAY_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); } /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know diff --git a/parachains/runtimes/assets/statemine/src/xcm_config.rs b/parachains/runtimes/assets/statemine/src/xcm_config.rs index 5f4dacda475..afc246fb586 100644 --- a/parachains/runtimes/assets/statemine/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemine/src/xcm_config.rs @@ -18,6 +18,7 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess}, @@ -28,9 +29,10 @@ use parachains_common::{ xcm_config::{ AssetFeeAsExistentialDepositMultiplier, DenyReserveTransferToRelayChain, DenyThenTry, }, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; -use sp_runtime::traits::ConvertInto; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -133,6 +135,7 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmAssetFeesReceiver: Option = Authorship::author(); + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); } match_types! { @@ -351,7 +354,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/assets/statemint/src/xcm_config.rs b/parachains/runtimes/assets/statemint/src/xcm_config.rs index 810832d54e9..05f38c263f4 100644 --- a/parachains/runtimes/assets/statemint/src/xcm_config.rs +++ b/parachains/runtimes/assets/statemint/src/xcm_config.rs @@ -18,6 +18,7 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess}, @@ -28,9 +29,10 @@ use parachains_common::{ xcm_config::{ AssetFeeAsExistentialDepositMultiplier, DenyReserveTransferToRelayChain, DenyThenTry, }, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; -use sp_runtime::traits::ConvertInto; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -133,6 +135,7 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmAssetFeesReceiver: Option = Authorship::author(); + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); } match_types! { @@ -317,7 +320,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/assets/westmint/src/xcm_config.rs b/parachains/runtimes/assets/westmint/src/xcm_config.rs index 064094e03d3..138fa29371a 100644 --- a/parachains/runtimes/assets/westmint/src/xcm_config.rs +++ b/parachains/runtimes/assets/westmint/src/xcm_config.rs @@ -18,6 +18,7 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess}, @@ -28,9 +29,10 @@ use parachains_common::{ xcm_config::{ AssetFeeAsExistentialDepositMultiplier, DenyReserveTransferToRelayChain, DenyThenTry, }, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; -use sp_runtime::traits::ConvertInto; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -131,6 +133,7 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub XcmAssetFeesReceiver: Option = Authorship::author(); + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); } match_types! { @@ -344,7 +347,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs index b9992438c83..eae310ce537 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/xcm_config.rs @@ -18,16 +18,19 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, }; use pallet_xcm::XcmPassthrough; -use parachains_common::xcm_config::{ - ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry, +use parachains_common::{ + xcm_config::{ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry}, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -47,6 +50,7 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); pub const FellowshipLocation: MultiLocation = MultiLocation::parent(); } @@ -205,7 +209,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs index e52bca88daf..056c33ed7ce 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/xcm_config.rs @@ -18,16 +18,19 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, }; use pallet_xcm::XcmPassthrough; -use parachains_common::xcm_config::{ - ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry, +use parachains_common::{ + xcm_config::{ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry}, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -47,6 +50,7 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); pub FellowshipLocation: MultiLocation = MultiLocation::new(1, Parachain(1001)); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); } @@ -205,7 +209,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 3067cb3f507..f41cb741210 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -18,16 +18,19 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, }; use pallet_xcm::XcmPassthrough; -use parachains_common::xcm_config::{ - ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry, +use parachains_common::{ + xcm_config::{ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry}, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -47,6 +50,7 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -203,7 +207,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index 3e63b6fe7c2..2a6da2e2343 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -17,6 +17,7 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, Fellows, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use cumulus_primitives_utility::XcmFeeManagerToAccount; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, @@ -26,8 +27,10 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ConcreteNativeAssetFrom, DenyReserveTransferToRelayChain, DenyThenTry}, + RELAY_TREASURY_PALLET_ID, }; use polkadot_parachain::primitives::Sibling; +use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -105,6 +108,7 @@ parameter_types! { pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiverToTreasury: Option = Some(RELAY_TREASURY_PALLET_ID.into_account_truncating()); // Fellows pluralistic body. pub const FellowsBodyId: BodyId = BodyId::Technical; } @@ -241,7 +245,8 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = + XcmFeeManagerToAccount; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; diff --git a/primitives/utility/src/lib.rs b/primitives/utility/src/lib.rs index d3a7c77aed2..4131645db68 100644 --- a/primitives/utility/src/lib.rs +++ b/primitives/utility/src/lib.rs @@ -33,7 +33,7 @@ use sp_runtime::{traits::Saturating, SaturatedConversion}; use sp_std::{marker::PhantomData, prelude::*}; use xcm::{latest::prelude::*, WrapVersion}; use xcm_builder::TakeRevenue; -use xcm_executor::traits::{MatchesFungibles, TransactAsset, WeightTrader}; +use xcm_executor::traits::{FeeManager, FeeReason, MatchesFungibles, TransactAsset, WeightTrader}; pub trait PriceForParentDelivery { fn price_for_parent_delivery(message: &Xcm<()>) -> MultiAssets; @@ -270,7 +270,7 @@ impl< } /// XCM fee depositor to which we implement the TakeRevenue trait -/// It receives a Transact implemented argument, a 32 byte convertible acocuntId, and the fee receiver account +/// It receives a Transact implemented argument, a 32 byte convertible accountId, and the fee receiver account /// FungiblesMutateAdapter should be identical to that implemented by WithdrawAsset pub struct XcmFeesTo32ByteAccount( PhantomData<(FungiblesMutateAdapter, AccountId, ReceiverAccount)>, @@ -297,6 +297,43 @@ impl< } } +pub struct XcmFeeManagerToAccount +where + FungiblesMutateAdapter: xcm_executor::traits::TransactAsset, +{ + _phantom: PhantomData<(FungiblesMutateAdapter, AccountId, ReceiverAccount)>, +} + +impl FeeManager + for XcmFeeManagerToAccount +where + FungiblesMutateAdapter: xcm_executor::traits::TransactAsset, + AccountId: Clone + Into<[u8; 32]>, + ReceiverAccount: frame_support::traits::Get>, +{ + fn is_waived(_origin: Option<&MultiLocation>, _: FeeReason) -> bool { + false + } + + fn handle_fee(fee: MultiAssets) { + if let Some(receiver) = ReceiverAccount::get() { + let dest = X1(AccountId32 { network: None, id: receiver.into() }).into(); + for asset in fee.into_inner() { + let ok = FungiblesMutateAdapter::deposit_asset( + &asset, + &dest, + // We aren't able to track the XCM that initiated the fee deposit, so we create a + // fake message hash here + &XcmContext::with_message_hash([0; 32]), + ) + .is_ok(); + + debug_assert!(ok, "`deposit_asset` cannot generally fail"); + } + } + } +} + /// ChargeWeightInFungibles trait, which converts a given amount of weight /// and an assetId, and it returns the balance amount that should be charged /// in such assetId for that amount of weight From 352e01c4c2ea98c00c6f0997164e9a005aebc0f8 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Wed, 22 Mar 2023 10:50:42 +0000 Subject: [PATCH 2/2] Wave XCM fees for relay chain governance. --- primitives/utility/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/utility/src/lib.rs b/primitives/utility/src/lib.rs index 4131645db68..1c5158522ee 100644 --- a/primitives/utility/src/lib.rs +++ b/primitives/utility/src/lib.rs @@ -311,8 +311,8 @@ where AccountId: Clone + Into<[u8; 32]>, ReceiverAccount: frame_support::traits::Get>, { - fn is_waived(_origin: Option<&MultiLocation>, _: FeeReason) -> bool { - false + fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool { + matches!(origin, Some(MultiLocation { parents: 1, interior: Here })) } fn handle_fee(fee: MultiAssets) {