Introduce XcmFeesToAccount fee manager (#1234)

Combination of paritytech/polkadot#7005, its addon PR
paritytech/polkadot#7585 and its companion paritytech/cumulus#2433.

This PR introduces a new XcmFeesToAccount struct which implements the
`FeeManager` trait, and assigns this struct as the `FeeManager` in the
XCM config for all runtimes.

The struct simply deposits all fees handled by the XCM executor to a
specified account. In all runtimes, the specified account is configured
as the treasury account.

XCM __delivery__ fees are now being introduced (unless the root origin
is sending a message to a system parachain on behalf of the originating
chain).

# Note for reviewers

Most file changes are tests that had to be modified to account for the
new fees.
Main changes are in:
- cumulus/pallets/xcmp-queue/src/lib.rs <- To make it track the delivery
fees exponential factor
- polkadot/xcm/xcm-builder/src/fee_handling.rs <- Added. Has the
FeeManager implementation
- All runtime xcm_config files <- To add the FeeManager to the XCM
configuration

# Important note

After this change, instructions that create and send a new XCM (Query*,
Report*, ExportMessage, InitiateReserveWithdraw, InitiateTeleport,
DepositReserveAsset, TransferReserveAsset, LockAsset and RequestUnlock)
will require the corresponding origin account in the origin register to
pay for transport delivery fees, and the onward message will fail to be
sent if the origin account does not have the required amount. This
delivery fee is on top of what we already collect as tx fees in
pallet-xcm and XCM BuyExecution fees!

Wallet UIs that want to expose the new delivery fee can do so using the
formula:

```
delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee)
```

where the delivery fee factor can be obtained from the corresponding
pallet based on which transport you are using (UMP, HRMP or bridges),
the base fee is a constant, the encoded message length from the message
itself and the per byte fee is the same as the configured per byte fee
for txs (i.e. `TransactionByteFee`).

---------

Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: Giles Cope <gilescope@gmail.com>
Co-authored-by: command-bot <>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Keith Yeung
2023-10-18 23:22:25 +08:00
committed by GitHub
parent 1cf7d3aafa
commit 3dece311be
99 changed files with 2229 additions and 468 deletions
+16
View File
@@ -2182,9 +2182,24 @@ sp_api::impl_runtime_apis! {
};
use xcm_config::{AssetHub, TokenLocation};
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
TokenLocation::get(),
ExistentialDeposit::get()
).into());
pub ToParachain: ParaId = westend_runtime_constants::system_parachain::ASSET_HUB_ID.into();
}
impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = xcm_config::XcmConfig;
type AccountIdConverter = xcm_config::LocationConverter;
type DeliveryHelper = runtime_common::xcm_sender::ToParachainDeliveryHelper<
xcm_config::XcmConfig,
ExistentialDepositMultiAsset,
xcm_config::PriceForChildParachainDelivery,
ToParachain,
(),
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
Ok(AssetHub::get())
}
@@ -2221,6 +2236,7 @@ sp_api::impl_runtime_apis! {
}
impl pallet_xcm_benchmarks::generic::Config for Runtime {
type TransactAsset = Balances;
type RuntimeCall = RuntimeCall;
fn worst_case_response() -> (u64, Response) {
@@ -17,7 +17,7 @@
//! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-10-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-nbnwcyh-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
@@ -55,8 +55,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `101`
// Estimated: `3593`
// Minimum execution time: 24_642_000 picoseconds.
Weight::from_parts(24_973_000, 3593)
// Minimum execution time: 24_815_000 picoseconds.
Weight::from_parts(25_098_000, 3593)
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -66,8 +66,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `101`
// Estimated: `6196`
// Minimum execution time: 50_882_000 picoseconds.
Weight::from_parts(51_516_000, 6196)
// Minimum execution time: 51_268_000 picoseconds.
Weight::from_parts(51_857_000, 6196)
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -85,8 +85,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `210`
// Estimated: `6196`
// Minimum execution time: 73_923_000 picoseconds.
Weight::from_parts(75_454_000, 6196)
// Minimum execution time: 74_113_000 picoseconds.
Weight::from_parts(74_721_000, 6196)
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(4))
}
@@ -111,8 +111,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `109`
// Estimated: `3574`
// Minimum execution time: 29_035_000 picoseconds.
Weight::from_parts(30_086_000, 3574)
// Minimum execution time: 28_919_000 picoseconds.
Weight::from_parts(29_703_000, 3574)
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -122,8 +122,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `103`
// Estimated: `3593`
// Minimum execution time: 22_094_000 picoseconds.
Weight::from_parts(22_560_000, 3593)
// Minimum execution time: 21_685_000 picoseconds.
Weight::from_parts(22_528_000, 3593)
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -133,8 +133,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `3593`
// Minimum execution time: 24_771_000 picoseconds.
Weight::from_parts(25_280_000, 3593)
// Minimum execution time: 25_192_000 picoseconds.
Weight::from_parts(25_445_000, 3593)
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -152,8 +152,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `109`
// Estimated: `3593`
// Minimum execution time: 49_777_000 picoseconds.
Weight::from_parts(50_833_000, 3593)
// Minimum execution time: 49_349_000 picoseconds.
Weight::from_parts(50_476_000, 3593)
.saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(3))
}
@@ -171,8 +171,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `109`
// Estimated: `3593`
// Minimum execution time: 51_425_000 picoseconds.
Weight::from_parts(52_213_000, 3593)
// Minimum execution time: 51_386_000 picoseconds.
Weight::from_parts(52_141_000, 3593)
.saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(3))
}
+24 -18
View File
@@ -19,7 +19,7 @@
use super::{
parachains_origin, AccountId, AllPalletsWithSystem, Balances, Dmp, FellowshipAdmin,
GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin,
TransactionByteFee, WeightToFee, XcmPallet,
TransactionByteFee, Treasury, WeightToFee, XcmPallet,
};
use frame_support::{
@@ -44,6 +44,7 @@ use xcm_builder::{
DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeesToAccount,
};
use xcm_executor::XcmExecutor;
@@ -53,6 +54,7 @@ parameter_types! {
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
pub CheckAccount: AccountId = XcmPallet::check_account();
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
pub TreasuryAccount: Option<AccountId> = Some(Treasury::account_id());
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(TokenLocation::get());
/// The base fee for the message delivery fees.
@@ -95,29 +97,38 @@ type LocalOriginConverter = (
XcmPassthrough<RuntimeOrigin>,
);
pub type PriceForChildParachainDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>;
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
/// individual routers.
pub type XcmRouter = WithUniqueTopic<(
pub type XcmRouter = WithUniqueTopic<
// Only one router so far - use DMP to communicate with child parachains.
ChildParachainRouter<
Runtime,
XcmPallet,
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
>,
)>;
ChildParachainRouter<Runtime, XcmPallet, PriceForChildParachainDelivery>,
>;
parameter_types! {
pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const AssetHub: MultiLocation = Parachain(ASSET_HUB_ID).into_location();
pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get());
pub const Collectives: MultiLocation = Parachain(COLLECTIVES_ID).into_location();
pub const BridgeHub: MultiLocation = Parachain(BRIDGE_HUB_ID).into_location();
pub const Wnd: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const WndForAssetHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), AssetHub::get());
pub const WndForCollectives: (MultiAssetFilter, MultiLocation) = (Wnd::get(), Collectives::get());
pub const WndForBridgeHub: (MultiAssetFilter, MultiLocation) = (Wnd::get(), BridgeHub::get());
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
}
pub type TrustedTeleporters =
(xcm_builder::Case<WndForAssetHub>, xcm_builder::Case<WndForCollectives>);
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
}
pub type TrustedTeleporters = (
xcm_builder::Case<WndForAssetHub>,
xcm_builder::Case<WndForCollectives>,
xcm_builder::Case<WndForBridgeHub>,
);
match_types! {
pub type OnlyParachains: impl Contains<MultiLocation> = {
@@ -174,7 +185,7 @@ impl xcm_executor::Config for XcmConfig {
type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = ();
type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
type MessageExporter = ();
type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall;
@@ -191,11 +202,6 @@ parameter_types! {
pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX);
}
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
}
/// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value.
pub type GeneralAdminToPlurality =
OriginToPluralityVoice<RuntimeOrigin, GeneralAdmin, GeneralAdminBodyId>;