use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo,
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee,
XcmpQueue,
};
use assets_common::{
matching::{FromSiblingParachain, IsForeignConcreteAsset, ParentLocation},
TrustBackedAssetsAsLocation,
};
use frame_support::{
parameter_types,
traits::{
tokens::imbalance::{ResolveAssetTo, ResolveTo},
ConstU32, Contains, Equals, Everything, PalletInfoAccess,
},
};
use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough;
use parachains_common::{
xcm_config::{
AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier,
ConcreteAssetFromSystem, RelayOrOtherSystemParachains,
},
TREASURY_PALLET_ID,
};
use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use snowbridge_router_primitives::inbound::EthereumLocationsConverterFor;
use sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto};
use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
use xcm_builder::{
AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom,
AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry,
DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor,
FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription,
IsConcrete, LocalMint, MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking,
NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter,
SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith,
StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithLatestLocationConverter, WithUniqueTopic,
XcmFeeManagerFromComponents,
};
use xcm_executor::XcmExecutor;
parameter_types! {
pub const RootLocation: Location = Location::here();
pub const WestendLocation: Location = Location::parent();
pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH));
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
pub UniversalLocation: InteriorLocation =
[GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into();
pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap();
pub TrustBackedAssetsPalletLocation: Location =
PalletInstance(TrustBackedAssetsPalletIndex::get()).into();
pub TrustBackedAssetsPalletIndex: u8 = <Assets as PalletInfoAccess>::index() as u8;
pub ForeignAssetsPalletLocation: Location =
PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into();
pub PoolAssetsPalletLocation: Location =
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub UniquesPalletLocation: Location =
PalletInstance(<Uniques as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
pub StakingPot: AccountId = CollatorSelection::account_id();
pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating();
pub RelayTreasuryLocation: Location = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into();
}
pub type LocationToAccountId = (
ParentIsPreset<AccountId>,
SiblingParachainConvertsVia<Sibling, AccountId>,
AccountId32Aliases<RelayNetwork, AccountId>,
HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>,
EthereumLocationsConverterFor<AccountId>,
);
pub type FungibleTransactor = FungibleAdapter<
Balances,
IsConcrete<WestendLocation>,
LocationToAccountId,
AccountId,
(),
>;
pub type TrustBackedAssetsConvertedConcreteId =
assets_common::TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance>;
pub type FungiblesTransactor = FungiblesAdapter<
Assets,
TrustBackedAssetsConvertedConcreteId,
LocationToAccountId,
AccountId,
LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, Assets>>,
CheckingAccount,
>;
pub type UniquesConvertedConcreteId =
assets_common::UniquesConvertedConcreteId<UniquesPalletLocation>;
pub type UniquesTransactor = NonFungiblesAdapter<
Uniques,
UniquesConvertedConcreteId,
LocationToAccountId,
AccountId,
NoChecking,
CheckingAccount,
>;
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
(
StartsWith<TrustBackedAssetsPalletLocation>,
StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
),
Balance,
xcm::v5::Location,
>;
pub type ForeignFungiblesTransactor = FungiblesAdapter<
ForeignAssets,
ForeignAssetsConvertedConcreteId,
LocationToAccountId,
AccountId,
NoChecking,
CheckingAccount,
>;
pub type PoolAssetsConvertedConcreteId =
assets_common::PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance>;
pub type PoolFungiblesTransactor = FungiblesAdapter<
PoolAssets,
PoolAssetsConvertedConcreteId,
LocationToAccountId,
AccountId,
LocalMint<parachains_common::impls::NonZeroIssuance<AccountId, PoolAssets>>,
CheckingAccount,
>;
pub type AssetTransactors = (
FungibleTransactor,
FungiblesTransactor,
ForeignFungiblesTransactor,
PoolFungiblesTransactor,
UniquesTransactor,
);
pub type XcmOriginToTransactDispatchOrigin = (
SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
ParentAsSuperuser<RuntimeOrigin>,
SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
XcmPassthrough<RuntimeOrigin>,
);
parameter_types! {
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
pub XcmAssetFeesReceiver: Option<AccountId> = Authorship::author();
}
pub struct ParentOrParentsPlurality;
impl Contains<Location> for ParentOrParentsPlurality {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, []) | (1, [Plurality { .. }]))
}
}
pub struct FellowshipEntities;
impl Contains<Location> for FellowshipEntities {
fn contains(location: &Location) -> bool {
matches!(
location.unpack(),
(1, [Parachain(1001), Plurality { id: BodyId::Technical, .. }]) |
(1, [Parachain(1001), PalletInstance(64)]) |
(1, [Parachain(1001), PalletInstance(65)])
)
}
}
pub struct AmbassadorEntities;
impl Contains<Location> for AmbassadorEntities {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, [Parachain(1001), PalletInstance(74)]))
}
}
pub type Barrier = TrailingSetTopicAsId<
DenyThenTry<
DenyReserveTransferToRelayChain,
(
TakeWeightCredit,
AllowKnownQueryResponses<PolkadotXcm>,
WithComputedOrigin<
(
AllowTopLevelPaidExecutionFrom<Everything>,
AllowExplicitUnpaidExecutionFrom<(
ParentOrParentsPlurality,
Equals<RelayTreasuryLocation>,
Equals<bridging::SiblingBridgeHub>,
FellowshipEntities,
AmbassadorEntities,
)>,
AllowSubscriptionsFrom<Everything>,
AllowHrmpNotificationsFromRelayChain,
),
UniversalLocation,
ConstU32<8>,
>,
),
>,
>;
pub type AssetFeeAsExistentialDepositMultiplierFeeCharger = AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto, TrustBackedAssetsInstance>,
TrustBackedAssetsInstance,
>;
pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger =
AssetFeeAsExistentialDepositMultiplier<
Runtime,
WeightToFee,
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto, ForeignAssetsInstance>,
ForeignAssetsInstance,
>;
pub type WaivedLocations = (
Equals<RootLocation>,
RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>,
Equals<RelayTreasuryLocation>,
FellowshipEntities,
AmbassadorEntities,
);
pub type TrustedTeleporters = (
ConcreteAssetFromSystem<WestendLocation>,
IsForeignConcreteAsset<FromSiblingParachain<parachain_info::Pallet<Runtime>>>,
);
pub type PoolAssetsExchanger = SingleAssetExchangeAdapter<
crate::AssetConversion,
crate::NativeAndAssets,
(
TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v5::Location>,
ForeignAssetsConvertedConcreteId,
MatchedConvertedConcreteId<
xcm::v5::Location,
Balance,
Equals<ParentLocation>,
WithLatestLocationConverter<xcm::v5::Location>,
TryConvertInto,
>,
),
AccountId,
>;
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
type XcmSender = XcmRouter;
type AssetTransactor = AssetTransactors;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
type IsReserve = (
bridging::to_rococo::RococoAssetFromAssetHubRococo,
bridging::to_ethereum::EthereumAssetFromEthereum,
);
type IsTeleporter = TrustedTeleporters;
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
type Weigher = WeightInfoBounds<
crate::weights::xcm::AssetHubWestendXcmWeight<RuntimeCall>,
RuntimeCall,
MaxInstructions,
>;
type Trader = (
UsingComponents<
WeightToFee,
WestendLocation,
AccountId,
Balances,
ResolveTo<StakingPot, Balances>,
>,
cumulus_primitives_utility::SwapFirstAssetTrader<
WestendLocation,
crate::AssetConversion,
WeightToFee,
crate::NativeAndAssets,
(
TrustBackedAssetsAsLocation<
TrustBackedAssetsPalletLocation,
Balance,
xcm::v5::Location,
>,
ForeignAssetsConvertedConcreteId,
),
ResolveAssetTo<StakingPot, crate::NativeAndAssets>,
AccountId,
>,
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
AssetFeeAsExistentialDepositMultiplierFeeCharger,
TrustBackedAssetsConvertedConcreteId,
Assets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
FungiblesTransactor,
AccountId,
XcmAssetFeesReceiver,
>,
>,
cumulus_primitives_utility::TakeFirstAssetTrader<
AccountId,
ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger,
ForeignAssetsConvertedConcreteId,
ForeignAssets,
cumulus_primitives_utility::XcmFeesTo32ByteAccount<
ForeignFungiblesTransactor,
AccountId,
XcmAssetFeesReceiver,
>,
>,
);
type ResponseHandler = PolkadotXcm;
type AssetTrap = PolkadotXcm;
type AssetClaims = PolkadotXcm;
type SubscriptionService = PolkadotXcm;
type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type AssetLocker = ();
type AssetExchanger = PoolAssetsExchanger;
type FeeManager = XcmFeeManagerFromComponents<
WaivedLocations,
SendXcmFeeToAccount<Self::AssetTransactor, TreasuryAccount>,
>;
type MessageExporter = ();
type UniversalAliases =
(bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases);
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = AliasChildLocation;
type TransactionalProcessor = FrameTransactionalProcessor;
type HrmpNewChannelOpenRequestHandler = ();
type HrmpChannelAcceptedHandler = ();
type HrmpChannelClosingHandler = ();
type XcmRecorder = PolkadotXcm;
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
type LocalXcmRouter = (
cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
XcmpQueue,
);
pub type XcmRouter = WithUniqueTopic<(
LocalXcmRouter,
ToRococoXcmRouter,
SovereignPaidRemoteExporter<
bridging::to_ethereum::EthereumNetworkExportTable,
XcmpQueue,
UniversalLocation,
>,
)>;
impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Everything;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Everything;
type XcmReserveTransferFilter = Everything;
type Weigher = WeightInfoBounds<
crate::weights::xcm::AssetHubWestendXcmWeight<RuntimeCall>,
RuntimeCall,
MaxInstructions,
>;
type UniversalLocation = UniversalLocation;
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
type Currency = Balances;
type CurrencyMatcher = ();
type TrustedLockers = ();
type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = ();
}
impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
pub struct XcmBenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl pallet_assets::BenchmarkHelper<xcm::v5::Location> for XcmBenchmarkHelper {
fn create_asset_id_parameter(id: u32) -> xcm::v5::Location {
xcm::v5::Location::new(1, [xcm::v5::Junction::Parachain(id)])
}
}
pub mod bridging {
use super::*;
use alloc::collections::btree_set::BTreeSet;
use assets_common::matching;
parameter_types! {
pub storage XcmBridgeHubRouterBaseFee: Balance =
bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()
.saturating_add(bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get())
.saturating_add(bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds::get());
pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get();
pub SiblingBridgeHubParaId: u32 = bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID;
pub SiblingBridgeHub: Location = Location::new(1, [Parachain(SiblingBridgeHubParaId::get())]);
pub XcmBridgeHubRouterFeeAssetId: AssetId = WestendLocation::get().into();
pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> =
alloc::vec::Vec::new().into_iter()
.chain(to_rococo::BridgeTable::get())
.collect();
}
pub type NetworkExportTable = xcm_builder::NetworkExportTable<BridgeTable>;
pub mod to_rococo {
use super::*;
parameter_types! {
pub SiblingBridgeHubWithBridgeHubRococoInstance: Location = Location::new(
1,
[
Parachain(SiblingBridgeHubParaId::get()),
PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)
]
);
pub const RococoNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
pub RococoEcosystem: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]);
pub RocLocation: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]);
pub AssetHubRococo: Location = Location::new(2, [
GlobalConsensus(RococoNetwork::get()),
Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)
]);
pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> = alloc::vec![
NetworkExportTableItem::new(
RococoNetwork::get(),
Some(alloc::vec![
AssetHubRococo::get().interior.split_global().expect("invalid configuration for AssetHubRococo").1,
]),
SiblingBridgeHub::get(),
Some((
XcmBridgeHubRouterFeeAssetId::get(),
XcmBridgeHubRouterBaseFee::get(),
).into())
)
];
pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
alloc::vec![
(SiblingBridgeHubWithBridgeHubRococoInstance::get(), GlobalConsensus(RococoNetwork::get()))
]
);
}
impl Contains<(Location, Junction)> for UniversalAliases {
fn contains(alias: &(Location, Junction)) -> bool {
UniversalAliases::get().contains(alias)
}
}
pub type RococoAssetFromAssetHubRococo =
matching::RemoteAssetFromLocation<StartsWith<RococoEcosystem>, AssetHubRococo>;
}
pub mod to_ethereum {
use super::*;
use assets_common::matching::FromNetwork;
use sp_std::collections::btree_set::BTreeSet;
use testnet_parachains_constants::westend::snowbridge::{
EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX,
};
parameter_types! {
pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000;
pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get();
pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new(
1,
[
Parachain(SiblingBridgeHubParaId::get()),
PalletInstance(INBOUND_QUEUE_PALLET_INDEX)
]
);
pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec![
NetworkExportTableItem::new(
EthereumNetwork::get().into(),
Some(sp_std::vec![Junctions::Here]),
SiblingBridgeHub::get(),
Some((
XcmBridgeHubRouterFeeAssetId::get(),
BridgeHubEthereumBaseFee::get(),
).into())
),
];
pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
sp_std::vec![
(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())),
]
);
pub EthereumBridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec::Vec::new().into_iter()
.chain(BridgeTable::get())
.collect();
}
pub type EthereumNetworkExportTable = xcm_builder::NetworkExportTable<EthereumBridgeTable>;
pub type EthereumAssetFromEthereum =
IsForeignConcreteAsset<FromNetwork<UniversalLocation, EthereumNetwork>>;
impl Contains<(Location, Junction)> for UniversalAliases {
fn contains(alias: &(Location, Junction)) -> bool {
UniversalAliases::get().contains(alias)
}
}
}
#[cfg(feature = "runtime-benchmarks")]
pub struct BridgingBenchmarksHelper;
#[cfg(feature = "runtime-benchmarks")]
impl BridgingBenchmarksHelper {
pub fn prepare_universal_alias() -> Option<(Location, Junction)> {
let alias =
to_rococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| {
match to_rococo::SiblingBridgeHubWithBridgeHubRococoInstance::get()
.eq(&location)
{
true => Some((location, junction)),
false => None,
}
});
Some(alias.expect("we expect here BridgeHubWestend to Rococo mapping at least"))
}
}
}