mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 18:27:56 +00:00
Direct XCM ExportMessage fees for different bridges to different receiver accounts (#2021)
This commit is contained in:
@@ -53,7 +53,7 @@ use xcm_builder::{
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
XcmFeesToAccount,
|
||||
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||
|
||||
@@ -75,7 +75,7 @@ parameter_types! {
|
||||
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||
pub const GovernanceLocation: MultiLocation = MultiLocation::parent();
|
||||
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
|
||||
pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
|
||||
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into();
|
||||
}
|
||||
|
||||
@@ -619,7 +619,10 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
WaivedLocations,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases =
|
||||
(bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases);
|
||||
|
||||
@@ -683,7 +683,7 @@ mod asset_hub_rococo_tests {
|
||||
bridging_to_asset_hub_wococo,
|
||||
WeightLimit::Unlimited,
|
||||
Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()),
|
||||
Some(xcm_config::TreasuryAccount::get().unwrap()),
|
||||
Some(xcm_config::TreasuryAccount::get()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -871,7 +871,7 @@ mod asset_hub_wococo_tests {
|
||||
with_wococo_flavor_bridging_to_asset_hub_rococo,
|
||||
WeightLimit::Unlimited,
|
||||
Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()),
|
||||
Some(xcm_config::TreasuryAccount::get().unwrap()),
|
||||
Some(xcm_config::TreasuryAccount::get()),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ use xcm_builder::{
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
XcmFeesToAccount,
|
||||
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||
|
||||
@@ -73,7 +73,7 @@ parameter_types! {
|
||||
pub PoolAssetsPalletLocation: MultiLocation =
|
||||
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
|
||||
pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
|
||||
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into();
|
||||
}
|
||||
|
||||
@@ -562,7 +562,10 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
WaivedLocations,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
|
||||
@@ -24,9 +24,18 @@ use crate::{
|
||||
BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance,
|
||||
RequiredStakeForStakeAndSlash,
|
||||
},
|
||||
bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter,
|
||||
bridge_hub_wococo_config::ToBridgeHubRococoHaulBlobExporter,
|
||||
bridge_hub_rococo_config::{
|
||||
AssetHubRococoParaId, BridgeHubWococoChainId, BridgeHubWococoMessagesLane,
|
||||
ToBridgeHubWococoHaulBlobExporter, WococoGlobalConsensusNetwork,
|
||||
},
|
||||
bridge_hub_wococo_config::{
|
||||
AssetHubWococoParaId, BridgeHubRococoChainId, BridgeHubRococoMessagesLane,
|
||||
RococoGlobalConsensusNetwork, ToBridgeHubRococoHaulBlobExporter,
|
||||
},
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams};
|
||||
use bp_runtime::ChainId;
|
||||
use frame_support::{
|
||||
match_types, parameter_types,
|
||||
traits::{ConstU32, Contains, Equals, Everything, Nothing},
|
||||
@@ -43,18 +52,20 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice;
|
||||
use rococo_runtime_constants::system_parachain;
|
||||
use sp_core::Get;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter,
|
||||
DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser,
|
||||
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
XcmFeesToAccount,
|
||||
deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom,
|
||||
AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
|
||||
CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, HandleFee,
|
||||
IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
|
||||
XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::{
|
||||
traits::{ExportXcm, WithOriginFilter},
|
||||
traits::{ExportXcm, FeeReason, TransactAsset, WithOriginFilter},
|
||||
XcmExecutor,
|
||||
};
|
||||
|
||||
@@ -66,7 +77,7 @@ parameter_types! {
|
||||
X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into()));
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
||||
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
|
||||
pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
|
||||
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into();
|
||||
}
|
||||
|
||||
@@ -290,7 +301,26 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type SubscriptionService = PolkadotXcm;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
WaivedLocations,
|
||||
(
|
||||
XcmExportFeeToRelayerRewardAccounts<
|
||||
Self::AssetTransactor,
|
||||
WococoGlobalConsensusNetwork,
|
||||
AssetHubWococoParaId,
|
||||
BridgeHubWococoChainId,
|
||||
BridgeHubWococoMessagesLane,
|
||||
>,
|
||||
XcmExportFeeToRelayerRewardAccounts<
|
||||
Self::AssetTransactor,
|
||||
RococoGlobalConsensusNetwork,
|
||||
AssetHubRococoParaId,
|
||||
BridgeHubRococoChainId,
|
||||
BridgeHubRococoMessagesLane,
|
||||
>,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
),
|
||||
>;
|
||||
type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter;
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||
@@ -401,3 +431,96 @@ impl ExportXcm for BridgeHubRococoOrBridgeHubWococoSwitchExporter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `HandleFee` implementation that simply deposits the fees for `ExportMessage` XCM instructions
|
||||
/// into the accounts that are used for paying the relayer rewards.
|
||||
/// Burns the fees in case of a failure.
|
||||
pub struct XcmExportFeeToRelayerRewardAccounts<
|
||||
AssetTransactor,
|
||||
DestNetwork,
|
||||
DestParaId,
|
||||
DestBridgeHubId,
|
||||
BridgeLaneId,
|
||||
>(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgeHubId, BridgeLaneId)>);
|
||||
|
||||
impl<
|
||||
AssetTransactor: TransactAsset,
|
||||
DestNetwork: Get<NetworkId>,
|
||||
DestParaId: Get<cumulus_primitives_core::ParaId>,
|
||||
DestBridgeHubId: Get<ChainId>,
|
||||
BridgeLaneId: Get<LaneId>,
|
||||
> HandleFee
|
||||
for XcmExportFeeToRelayerRewardAccounts<
|
||||
AssetTransactor,
|
||||
DestNetwork,
|
||||
DestParaId,
|
||||
DestBridgeHubId,
|
||||
BridgeLaneId,
|
||||
>
|
||||
{
|
||||
fn handle_fee(
|
||||
fee: MultiAssets,
|
||||
maybe_context: Option<&XcmContext>,
|
||||
reason: FeeReason,
|
||||
) -> MultiAssets {
|
||||
if matches!(reason, FeeReason::Export { network: bridged_network, destination }
|
||||
if bridged_network == DestNetwork::get() &&
|
||||
destination == X1(Parachain(DestParaId::get().into())))
|
||||
{
|
||||
// We have 2 relayer rewards accounts:
|
||||
// - the SA of the source parachain on this BH: this pays the relayers for delivering
|
||||
// Source para -> Target Para message delivery confirmations
|
||||
// - the SA of the destination parachain on this BH: this pays the relayers for
|
||||
// delivering Target para -> Source Para messages
|
||||
// We split the `ExportMessage` fee between these 2 accounts.
|
||||
let source_para_account = PayRewardFromAccount::<
|
||||
pallet_balances::Pallet<Runtime>,
|
||||
AccountId,
|
||||
>::rewards_account(RewardsAccountParams::new(
|
||||
BridgeLaneId::get(),
|
||||
DestBridgeHubId::get(),
|
||||
RewardsAccountOwner::ThisChain,
|
||||
));
|
||||
|
||||
let dest_para_account = PayRewardFromAccount::<
|
||||
pallet_balances::Pallet<Runtime>,
|
||||
AccountId,
|
||||
>::rewards_account(RewardsAccountParams::new(
|
||||
BridgeLaneId::get(),
|
||||
DestBridgeHubId::get(),
|
||||
RewardsAccountOwner::BridgedChain,
|
||||
));
|
||||
|
||||
for asset in fee.into_inner() {
|
||||
match asset.fun {
|
||||
Fungible(total_fee) => {
|
||||
let source_fee = total_fee / 2;
|
||||
deposit_or_burn_fee::<AssetTransactor, _>(
|
||||
MultiAsset { id: asset.id, fun: Fungible(source_fee) }.into(),
|
||||
maybe_context,
|
||||
source_para_account.clone(),
|
||||
);
|
||||
|
||||
let dest_fee = total_fee - source_fee;
|
||||
deposit_or_burn_fee::<AssetTransactor, _>(
|
||||
MultiAsset { id: asset.id, fun: Fungible(dest_fee) }.into(),
|
||||
maybe_context,
|
||||
dest_para_account.clone(),
|
||||
);
|
||||
},
|
||||
NonFungible(_) => {
|
||||
deposit_or_burn_fee::<AssetTransactor, _>(
|
||||
asset.into(),
|
||||
maybe_context,
|
||||
source_para_account.clone(),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return MultiAssets::new()
|
||||
}
|
||||
|
||||
fee
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ use xcm_builder::{
|
||||
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||
WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
|
||||
WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
@@ -51,7 +51,7 @@ parameter_types! {
|
||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||
pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
|
||||
pub const ExecutiveBody: BodyId = BodyId::Executive;
|
||||
pub TreasuryAccount: Option<AccountId> = Some(TREASURY_PALLET_ID.into_account_truncating());
|
||||
pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
|
||||
pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into();
|
||||
}
|
||||
|
||||
@@ -199,7 +199,10 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type MaxAssetsIntoHolding = ConstU32<8>;
|
||||
type AssetLocker = ();
|
||||
type AssetExchanger = ();
|
||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
WaivedLocations,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
|
||||
@@ -43,7 +43,8 @@ use xcm_builder::{
|
||||
DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete,
|
||||
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
|
||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
|
||||
XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
@@ -53,7 +54,7 @@ parameter_types! {
|
||||
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
||||
pub TreasuryAccount: Option<AccountId> = Some(Treasury::account_id());
|
||||
pub TreasuryAccount: AccountId = Treasury::account_id();
|
||||
}
|
||||
|
||||
pub type LocationConverter = (
|
||||
@@ -191,7 +192,10 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
SystemParachains,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
|
||||
@@ -44,7 +44,7 @@ use xcm_builder::{
|
||||
DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
|
||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||
XcmFeesToAccount,
|
||||
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
@@ -54,7 +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());
|
||||
pub TreasuryAccount: AccountId = 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.
|
||||
@@ -185,7 +185,10 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
SystemParachains,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
type CallDispatcher = RuntimeCall;
|
||||
|
||||
@@ -561,7 +561,7 @@ benchmarks! {
|
||||
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
|
||||
&origin,
|
||||
&destination.into(),
|
||||
FeeReason::Export(network),
|
||||
FeeReason::Export { network, destination },
|
||||
);
|
||||
let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap();
|
||||
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
|
||||
|
||||
@@ -34,7 +34,7 @@ use xcm_builder::{
|
||||
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
|
||||
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible,
|
||||
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount,
|
||||
SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
use xcm_executor::XcmExecutor;
|
||||
|
||||
@@ -343,11 +343,9 @@ impl xcm_executor::Config for XcmConfig {
|
||||
type SubscriptionService = XcmPallet;
|
||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||
type FeeManager = XcmFeesToAccount<
|
||||
Self,
|
||||
type FeeManager = XcmFeeManagerFromComponents<
|
||||
EverythingBut<XcmFeesNotWaivedLocations>,
|
||||
AccountId,
|
||||
XcmFeesTargetAccount,
|
||||
XcmFeeToAccount<Self::AssetTransactor, AccountId, XcmFeesTargetAccount>,
|
||||
>;
|
||||
type MessageExporter = ();
|
||||
type UniversalAliases = Nothing;
|
||||
|
||||
@@ -19,40 +19,103 @@ use frame_support::traits::{Contains, Get};
|
||||
use xcm::prelude::*;
|
||||
use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
|
||||
|
||||
/// A `FeeManager` implementation that simply deposits the fees handled into a specific on-chain
|
||||
/// `ReceiverAccount`.
|
||||
///
|
||||
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets, and also
|
||||
/// permits specifying `WaivedLocations` for locations that are privileged to not pay for fees. If
|
||||
/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be
|
||||
/// logged.
|
||||
pub struct XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>(
|
||||
PhantomData<(XcmConfig, WaivedLocations, AccountId, ReceiverAccount)>,
|
||||
/// Handles the fees that are taken by certain XCM instructions.
|
||||
pub trait HandleFee {
|
||||
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
||||
/// fees.
|
||||
///
|
||||
/// Returns any part of the fee that wasn't consumed.
|
||||
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason)
|
||||
-> MultiAssets;
|
||||
}
|
||||
|
||||
// Default `HandleFee` implementation that just burns the fee.
|
||||
impl HandleFee for () {
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) -> MultiAssets {
|
||||
MultiAssets::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
|
||||
impl HandleFee for Tuple {
|
||||
fn handle_fee(
|
||||
fee: MultiAssets,
|
||||
context: Option<&XcmContext>,
|
||||
reason: FeeReason,
|
||||
) -> MultiAssets {
|
||||
let mut unconsumed_fee = fee;
|
||||
for_tuples!( #(
|
||||
unconsumed_fee = Tuple::handle_fee(unconsumed_fee, context, reason);
|
||||
if unconsumed_fee.is_none() {
|
||||
return unconsumed_fee;
|
||||
}
|
||||
)* );
|
||||
|
||||
unconsumed_fee
|
||||
}
|
||||
}
|
||||
|
||||
/// A `FeeManager` implementation that permits the specified `WaivedLocations` to not pay for fees
|
||||
/// and that uses the provided `HandleFee` implementation otherwise.
|
||||
pub struct XcmFeeManagerFromComponents<WaivedLocations, HandleFee>(
|
||||
PhantomData<(WaivedLocations, HandleFee)>,
|
||||
);
|
||||
impl<
|
||||
XcmConfig: xcm_executor::Config,
|
||||
WaivedLocations: Contains<MultiLocation>,
|
||||
AccountId: Clone + Into<[u8; 32]>,
|
||||
ReceiverAccount: Get<Option<AccountId>>,
|
||||
> FeeManager for XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>
|
||||
impl<WaivedLocations: Contains<MultiLocation>, FeeHandler: HandleFee> FeeManager
|
||||
for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
|
||||
{
|
||||
fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool {
|
||||
let Some(loc) = origin else { return false };
|
||||
WaivedLocations::contains(loc)
|
||||
}
|
||||
|
||||
fn handle_fee(fees: MultiAssets, context: Option<&XcmContext>) {
|
||||
if let Some(receiver) = ReceiverAccount::get() {
|
||||
let dest = AccountId32 { network: None, id: receiver.into() }.into();
|
||||
for asset in fees.into_inner() {
|
||||
if let Err(e) = XcmConfig::AssetTransactor::deposit_asset(&asset, &dest, context) {
|
||||
log::trace!(
|
||||
target: "xcm::fees",
|
||||
"`AssetTransactor::deposit_asset` returned error: {:?}, burning fees: {:?}",
|
||||
e, asset,
|
||||
);
|
||||
}
|
||||
}
|
||||
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason) {
|
||||
FeeHandler::handle_fee(fee, context, reason);
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to deposit the given fee in the specified account.
|
||||
/// Burns the fee in case of a failure.
|
||||
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 32]>>(
|
||||
fee: MultiAssets,
|
||||
context: Option<&XcmContext>,
|
||||
receiver: AccountId,
|
||||
) {
|
||||
let dest = AccountId32 { network: None, id: receiver.into() }.into();
|
||||
for asset in fee.into_inner() {
|
||||
if let Err(e) = AssetTransactor::deposit_asset(&asset, &dest, context) {
|
||||
log::trace!(
|
||||
target: "xcm::fees",
|
||||
"`AssetTransactor::deposit_asset` returned error: {:?}. Burning fee: {:?}. \
|
||||
They might be burned.",
|
||||
e, asset,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `HandleFee` implementation that simply deposits the fees into a specific on-chain
|
||||
/// `ReceiverAccount`.
|
||||
///
|
||||
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets. If
|
||||
/// the `AssetTransactor` returns an error while calling `deposit_asset`, then a warning will be
|
||||
/// logged and the fee burned.
|
||||
pub struct XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>(
|
||||
PhantomData<(AssetTransactor, AccountId, ReceiverAccount)>,
|
||||
);
|
||||
|
||||
impl<
|
||||
AssetTransactor: TransactAsset,
|
||||
AccountId: Clone + Into<[u8; 32]>,
|
||||
ReceiverAccount: Get<AccountId>,
|
||||
> HandleFee for XcmFeeToAccount<AssetTransactor, AccountId, ReceiverAccount>
|
||||
{
|
||||
fn handle_fee(
|
||||
fee: MultiAssets,
|
||||
context: Option<&XcmContext>,
|
||||
_reason: FeeReason,
|
||||
) -> MultiAssets {
|
||||
deposit_or_burn_fee::<AssetTransactor, _>(fee, context, ReceiverAccount::get());
|
||||
|
||||
MultiAssets::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,9 @@ mod currency_adapter;
|
||||
pub use currency_adapter::CurrencyAdapter;
|
||||
|
||||
mod fee_handling;
|
||||
pub use fee_handling::XcmFeesToAccount;
|
||||
pub use fee_handling::{
|
||||
deposit_or_burn_fee, HandleFee, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||
};
|
||||
|
||||
mod fungibles_adapter;
|
||||
pub use fungibles_adapter::{
|
||||
|
||||
@@ -526,7 +526,8 @@ impl FeeManager for TestFeeManager {
|
||||
fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool {
|
||||
IS_WAIVED.with(|l| l.borrow().contains(&r))
|
||||
}
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
|
||||
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
|
||||
@@ -248,7 +248,7 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
|
||||
for asset in fees.inner() {
|
||||
Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?;
|
||||
}
|
||||
Config::FeeManager::handle_fee(fees, None);
|
||||
Config::FeeManager::handle_fee(fees, None, FeeReason::ChargeFees);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -851,7 +851,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
destination,
|
||||
xcm,
|
||||
)?;
|
||||
self.take_fee(fee, FeeReason::Export(network))?;
|
||||
self.take_fee(fee, FeeReason::Export { network, destination })?;
|
||||
Config::MessageExporter::deliver(ticket)?;
|
||||
Ok(())
|
||||
},
|
||||
@@ -962,7 +962,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
} else {
|
||||
self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into()
|
||||
};
|
||||
Config::FeeManager::handle_fee(paid, Some(&self.context));
|
||||
Config::FeeManager::handle_fee(paid, Some(&self.context), reason);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ use xcm::prelude::*;
|
||||
|
||||
/// Handle stuff to do with taking fees in certain XCM instructions.
|
||||
pub trait FeeManager {
|
||||
/// Determine if a fee which would normally payable should be waived.
|
||||
/// Determine if a fee should be waived.
|
||||
fn is_waived(origin: Option<&MultiLocation>, r: FeeReason) -> bool;
|
||||
|
||||
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
||||
/// fees.
|
||||
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>);
|
||||
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, r: FeeReason);
|
||||
}
|
||||
|
||||
/// Context under which a fee is paid.
|
||||
@@ -42,7 +42,7 @@ pub enum FeeReason {
|
||||
/// When the `QueryPallet` instruction is called.
|
||||
QueryPallet,
|
||||
/// When the `ExportMessage` instruction is called (and includes the network ID).
|
||||
Export(NetworkId),
|
||||
Export { network: NetworkId, destination: InteriorMultiLocation },
|
||||
/// The `charge_fees` API.
|
||||
ChargeFees,
|
||||
/// When the `LockAsset` instruction is called.
|
||||
@@ -55,5 +55,6 @@ impl FeeManager for () {
|
||||
fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool {
|
||||
false
|
||||
}
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
|
||||
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user