mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 18:11:03 +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,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
XcmFeesToAccount,
|
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ parameter_types! {
|
|||||||
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
||||||
pub const GovernanceLocation: MultiLocation = MultiLocation::parent();
|
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();
|
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 MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||||
type AssetLocker = ();
|
type AssetLocker = ();
|
||||||
type AssetExchanger = ();
|
type AssetExchanger = ();
|
||||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
|
WaivedLocations,
|
||||||
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||||
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases =
|
type UniversalAliases =
|
||||||
(bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases);
|
(bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases);
|
||||||
|
|||||||
@@ -683,7 +683,7 @@ mod asset_hub_rococo_tests {
|
|||||||
bridging_to_asset_hub_wococo,
|
bridging_to_asset_hub_wococo,
|
||||||
WeightLimit::Unlimited,
|
WeightLimit::Unlimited,
|
||||||
Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()),
|
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,
|
with_wococo_flavor_bridging_to_asset_hub_rococo,
|
||||||
WeightLimit::Unlimited,
|
WeightLimit::Unlimited,
|
||||||
Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()),
|
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,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
XcmFeesToAccount,
|
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ parameter_types! {
|
|||||||
pub PoolAssetsPalletLocation: MultiLocation =
|
pub PoolAssetsPalletLocation: MultiLocation =
|
||||||
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
|
||||||
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
|
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();
|
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 MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||||
type AssetLocker = ();
|
type AssetLocker = ();
|
||||||
type AssetExchanger = ();
|
type AssetExchanger = ();
|
||||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
|
WaivedLocations,
|
||||||
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||||
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
||||||
|
|||||||
@@ -24,9 +24,18 @@ use crate::{
|
|||||||
BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance,
|
BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance,
|
||||||
RequiredStakeForStakeAndSlash,
|
RequiredStakeForStakeAndSlash,
|
||||||
},
|
},
|
||||||
bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter,
|
bridge_hub_rococo_config::{
|
||||||
bridge_hub_wococo_config::ToBridgeHubRococoHaulBlobExporter,
|
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::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
traits::{ConstU32, Contains, Equals, Everything, Nothing},
|
traits::{ConstU32, Contains, Equals, Everything, Nothing},
|
||||||
@@ -43,18 +52,20 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice;
|
|||||||
use rococo_runtime_constants::system_parachain;
|
use rococo_runtime_constants::system_parachain;
|
||||||
use sp_core::Get;
|
use sp_core::Get;
|
||||||
use sp_runtime::traits::AccountIdConversion;
|
use sp_runtime::traits::AccountIdConversion;
|
||||||
|
use sp_std::marker::PhantomData;
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
use xcm_builder::{
|
use xcm_builder::{
|
||||||
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
|
deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom,
|
||||||
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter,
|
AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
|
||||||
DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser,
|
CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, HandleFee,
|
||||||
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
|
IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||||
XcmFeesToAccount,
|
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
|
||||||
|
XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::{
|
use xcm_executor::{
|
||||||
traits::{ExportXcm, WithOriginFilter},
|
traits::{ExportXcm, FeeReason, TransactAsset, WithOriginFilter},
|
||||||
XcmExecutor,
|
XcmExecutor,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,7 +77,7 @@ parameter_types! {
|
|||||||
X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into()));
|
X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into()));
|
||||||
pub const MaxInstructions: u32 = 100;
|
pub const MaxInstructions: u32 = 100;
|
||||||
pub const MaxAssetsIntoHolding: u32 = 64;
|
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();
|
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 SubscriptionService = PolkadotXcm;
|
||||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
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 MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter;
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
|
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,
|
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||||
WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
|
WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ parameter_types! {
|
|||||||
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
|
||||||
pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
|
pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
|
||||||
pub const ExecutiveBody: BodyId = BodyId::Executive;
|
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();
|
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 MaxAssetsIntoHolding = ConstU32<8>;
|
||||||
type AssetLocker = ();
|
type AssetLocker = ();
|
||||||
type AssetExchanger = ();
|
type AssetExchanger = ();
|
||||||
type FeeManager = XcmFeesToAccount<Self, WaivedLocations, AccountId, TreasuryAccount>;
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
|
WaivedLocations,
|
||||||
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||||
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
type CallDispatcher = RuntimeCall;
|
type CallDispatcher = RuntimeCall;
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ use xcm_builder::{
|
|||||||
DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete,
|
DescribeFamily, FixedWeightBounds, HashedDescription, IsChildSystemParachain, IsConcrete,
|
||||||
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeesToAccount,
|
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
|
||||||
|
XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ parameter_types! {
|
|||||||
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
|
||||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
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 = (
|
pub type LocationConverter = (
|
||||||
@@ -191,7 +192,10 @@ impl xcm_executor::Config for XcmConfig {
|
|||||||
type SubscriptionService = XcmPallet;
|
type SubscriptionService = XcmPallet;
|
||||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||||
type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
|
SystemParachains,
|
||||||
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||||
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
type CallDispatcher = RuntimeCall;
|
type CallDispatcher = RuntimeCall;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ use xcm_builder::{
|
|||||||
DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
|
DescribeFamily, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice,
|
||||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||||
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
XcmFeesToAccount,
|
XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ parameter_types! {
|
|||||||
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
|
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
|
||||||
pub CheckAccount: AccountId = XcmPallet::check_account();
|
pub CheckAccount: AccountId = XcmPallet::check_account();
|
||||||
pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
|
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.
|
/// The asset ID for the asset that we use to pay for message delivery fees.
|
||||||
pub FeeAssetId: AssetId = Concrete(TokenLocation::get());
|
pub FeeAssetId: AssetId = Concrete(TokenLocation::get());
|
||||||
/// The base fee for the message delivery fees.
|
/// The base fee for the message delivery fees.
|
||||||
@@ -185,7 +185,10 @@ impl xcm_executor::Config for XcmConfig {
|
|||||||
type SubscriptionService = XcmPallet;
|
type SubscriptionService = XcmPallet;
|
||||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||||
type FeeManager = XcmFeesToAccount<Self, SystemParachains, AccountId, TreasuryAccount>;
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
|
SystemParachains,
|
||||||
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
|
||||||
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
type CallDispatcher = RuntimeCall;
|
type CallDispatcher = RuntimeCall;
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ benchmarks! {
|
|||||||
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
|
let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery(
|
||||||
&origin,
|
&origin,
|
||||||
&destination.into(),
|
&destination.into(),
|
||||||
FeeReason::Export(network),
|
FeeReason::Export { network, destination },
|
||||||
);
|
);
|
||||||
let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap();
|
let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap();
|
||||||
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
|
let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use xcm_builder::{
|
|||||||
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
|
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
|
||||||
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible,
|
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible,
|
||||||
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
|
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, XcmFeesToAccount,
|
SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
};
|
};
|
||||||
use xcm_executor::XcmExecutor;
|
use xcm_executor::XcmExecutor;
|
||||||
|
|
||||||
@@ -343,11 +343,9 @@ impl xcm_executor::Config for XcmConfig {
|
|||||||
type SubscriptionService = XcmPallet;
|
type SubscriptionService = XcmPallet;
|
||||||
type PalletInstancesInfo = AllPalletsWithSystem;
|
type PalletInstancesInfo = AllPalletsWithSystem;
|
||||||
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
|
||||||
type FeeManager = XcmFeesToAccount<
|
type FeeManager = XcmFeeManagerFromComponents<
|
||||||
Self,
|
|
||||||
EverythingBut<XcmFeesNotWaivedLocations>,
|
EverythingBut<XcmFeesNotWaivedLocations>,
|
||||||
AccountId,
|
XcmFeeToAccount<Self::AssetTransactor, AccountId, XcmFeesTargetAccount>,
|
||||||
XcmFeesTargetAccount,
|
|
||||||
>;
|
>;
|
||||||
type MessageExporter = ();
|
type MessageExporter = ();
|
||||||
type UniversalAliases = Nothing;
|
type UniversalAliases = Nothing;
|
||||||
|
|||||||
@@ -19,40 +19,103 @@ use frame_support::traits::{Contains, Get};
|
|||||||
use xcm::prelude::*;
|
use xcm::prelude::*;
|
||||||
use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
|
use xcm_executor::traits::{FeeManager, FeeReason, TransactAsset};
|
||||||
|
|
||||||
/// A `FeeManager` implementation that simply deposits the fees handled into a specific on-chain
|
/// Handles the fees that are taken by certain XCM instructions.
|
||||||
/// `ReceiverAccount`.
|
pub trait HandleFee {
|
||||||
///
|
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
||||||
/// It reuses the `AssetTransactor` configured on the XCM executor to deposit fee assets, and also
|
/// fees.
|
||||||
/// 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
|
/// Returns any part of the fee that wasn't consumed.
|
||||||
/// logged.
|
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason)
|
||||||
pub struct XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>(
|
-> MultiAssets;
|
||||||
PhantomData<(XcmConfig, WaivedLocations, AccountId, ReceiverAccount)>,
|
}
|
||||||
|
|
||||||
|
// 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<
|
impl<WaivedLocations: Contains<MultiLocation>, FeeHandler: HandleFee> FeeManager
|
||||||
XcmConfig: xcm_executor::Config,
|
for XcmFeeManagerFromComponents<WaivedLocations, FeeHandler>
|
||||||
WaivedLocations: Contains<MultiLocation>,
|
|
||||||
AccountId: Clone + Into<[u8; 32]>,
|
|
||||||
ReceiverAccount: Get<Option<AccountId>>,
|
|
||||||
> FeeManager for XcmFeesToAccount<XcmConfig, WaivedLocations, AccountId, ReceiverAccount>
|
|
||||||
{
|
{
|
||||||
fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool {
|
fn is_waived(origin: Option<&MultiLocation>, _: FeeReason) -> bool {
|
||||||
let Some(loc) = origin else { return false };
|
let Some(loc) = origin else { return false };
|
||||||
WaivedLocations::contains(loc)
|
WaivedLocations::contains(loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_fee(fees: MultiAssets, context: Option<&XcmContext>) {
|
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>, reason: FeeReason) {
|
||||||
if let Some(receiver) = ReceiverAccount::get() {
|
FeeHandler::handle_fee(fee, context, reason);
|
||||||
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!(
|
/// Try to deposit the given fee in the specified account.
|
||||||
target: "xcm::fees",
|
/// Burns the fee in case of a failure.
|
||||||
"`AssetTransactor::deposit_asset` returned error: {:?}, burning fees: {:?}",
|
pub fn deposit_or_burn_fee<AssetTransactor: TransactAsset, AccountId: Clone + Into<[u8; 32]>>(
|
||||||
e, asset,
|
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;
|
pub use currency_adapter::CurrencyAdapter;
|
||||||
|
|
||||||
mod fee_handling;
|
mod fee_handling;
|
||||||
pub use fee_handling::XcmFeesToAccount;
|
pub use fee_handling::{
|
||||||
|
deposit_or_burn_fee, HandleFee, XcmFeeManagerFromComponents, XcmFeeToAccount,
|
||||||
|
};
|
||||||
|
|
||||||
mod fungibles_adapter;
|
mod fungibles_adapter;
|
||||||
pub use fungibles_adapter::{
|
pub use fungibles_adapter::{
|
||||||
|
|||||||
@@ -526,7 +526,8 @@ impl FeeManager for TestFeeManager {
|
|||||||
fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool {
|
fn is_waived(_: Option<&MultiLocation>, r: FeeReason) -> bool {
|
||||||
IS_WAIVED.with(|l| l.borrow().contains(&r))
|
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)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
|
|||||||
for asset in fees.inner() {
|
for asset in fees.inner() {
|
||||||
Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?;
|
Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?;
|
||||||
}
|
}
|
||||||
Config::FeeManager::handle_fee(fees, None);
|
Config::FeeManager::handle_fee(fees, None, FeeReason::ChargeFees);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -851,7 +851,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
destination,
|
destination,
|
||||||
xcm,
|
xcm,
|
||||||
)?;
|
)?;
|
||||||
self.take_fee(fee, FeeReason::Export(network))?;
|
self.take_fee(fee, FeeReason::Export { network, destination })?;
|
||||||
Config::MessageExporter::deliver(ticket)?;
|
Config::MessageExporter::deliver(ticket)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@@ -962,7 +962,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
} else {
|
} else {
|
||||||
self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into()
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ use xcm::prelude::*;
|
|||||||
|
|
||||||
/// Handle stuff to do with taking fees in certain XCM instructions.
|
/// Handle stuff to do with taking fees in certain XCM instructions.
|
||||||
pub trait FeeManager {
|
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;
|
fn is_waived(origin: Option<&MultiLocation>, r: FeeReason) -> bool;
|
||||||
|
|
||||||
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
||||||
/// fees.
|
/// 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.
|
/// Context under which a fee is paid.
|
||||||
@@ -42,7 +42,7 @@ pub enum FeeReason {
|
|||||||
/// When the `QueryPallet` instruction is called.
|
/// When the `QueryPallet` instruction is called.
|
||||||
QueryPallet,
|
QueryPallet,
|
||||||
/// When the `ExportMessage` instruction is called (and includes the network ID).
|
/// When the `ExportMessage` instruction is called (and includes the network ID).
|
||||||
Export(NetworkId),
|
Export { network: NetworkId, destination: InteriorMultiLocation },
|
||||||
/// The `charge_fees` API.
|
/// The `charge_fees` API.
|
||||||
ChargeFees,
|
ChargeFees,
|
||||||
/// When the `LockAsset` instruction is called.
|
/// When the `LockAsset` instruction is called.
|
||||||
@@ -55,5 +55,6 @@ impl FeeManager for () {
|
|||||||
fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool {
|
fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
|
|
||||||
|
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>, _: FeeReason) {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user