[testnet] Add AssetHubRococo <-> AssetHubWestend asset bridging support (#1967)

## Summary

Asset bridging support for AssetHub**Rococo** <-> AssetHub**Wococo** was
added [here](https://github.com/paritytech/polkadot-sdk/pull/1215), so
now we aim to bridge AssetHub**Rococo** and AssetHub**Westend**. (And
perhaps retire AssetHubWococo and the Wococo chains).

## Solution

**bridge-hub-westend-runtime**
- added new runtime as a copy of `bridge-hub-rococo-runtime`
- added support for bridging to `BridgeHubRococo`
- added tests and benchmarks

**bridge-hub-rococo-runtime**
- added support for bridging to `BridgeHubWestend`
- added tests and benchmarks
- internal refactoring by splitting bridge configuration per network,
e.g., `bridge_to_whatevernetwork_config.rs`.

**asset-hub-rococo-runtime**
- added support for asset bridging to `AssetHubWestend` (allows to
receive only WNDs)
- added new xcm router for `Westend`
- added tests and benchmarks

**asset-hub-westend-runtime**
- added support for asset bridging to `AssetHubRococo` (allows to
receive only ROCs)
- added new xcm router for `Rococo`
- added tests and benchmarks

## Deployment

All changes will be deployed as a part of
https://github.com/paritytech/polkadot-sdk/issues/1988.

## TODO

- [x] benchmarks for all pallet instances
- [x] integration tests
- [x] local run scripts


Relates to:
https://github.com/paritytech/parity-bridges-common/issues/2602
Relates to: https://github.com/paritytech/polkadot-sdk/issues/1988

---------

Co-authored-by: command-bot <>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
This commit is contained in:
Branislav Kontur
2023-11-02 00:39:49 +01:00
committed by GitHub
parent c66ae375e6
commit 1b1fab0da3
112 changed files with 10028 additions and 1638 deletions
@@ -17,8 +17,8 @@ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm,
PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeFlavor, RuntimeOrigin,
ToRococoXcmRouter, ToWococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance,
WeightToFee, XcmpQueue,
ToRococoXcmRouter, ToWestendXcmRouter, ToWococoXcmRouter, TransactionByteFee,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
@@ -44,16 +44,16 @@ use rococo_runtime_constants::system_parachain;
use sp_runtime::traits::{AccountIdConversion, ConvertInto};
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllAssets, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, CurrencyAdapter,
DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily,
EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription,
IsConcrete, LocalMint, LocationWithAssetFilters, NetworkExportTableItem, NoChecking,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith,
StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -260,10 +260,6 @@ match_types! {
MultiLocation { parents: 1, interior: Here } |
MultiLocation { parents: 1, interior: X1(_) }
};
pub type WithParentsZeroOrOne: impl Contains<MultiLocation> = {
MultiLocation { parents: 0, .. } |
MultiLocation { parents: 1, .. }
};
}
/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
@@ -478,6 +474,8 @@ impl Contains<RuntimeCall> for SafeCallFilter {
pallet_uniques::Call::buy_item { .. }
) | RuntimeCall::ToWococoXcmRouter(
pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. }
) | RuntimeCall::ToWestendXcmRouter(
pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. }
) | RuntimeCall::ToRococoXcmRouter(
pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. }
)
@@ -567,11 +565,13 @@ impl xcm_executor::Config for XcmConfig {
type XcmSender = XcmRouter;
type AssetTransactor = AssetTransactors;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
// Asset Hub trusts only particular configured bridge locations as reserve locations.
// Asset Hub may _act_ as a reserve location for ROC and assets created under `pallet-assets`.
// Users must use teleport where allowed (e.g. ROC with the Relay Chain).
// Asset Hub trusts only particular, pre-configured bridged locations from a different consensus
// as reserve locations (we trust the Bridge Hub to relay the message that a reserve is being
// held). Asset Hub may _act_ as a reserve location for ROC and assets created
// under `pallet-assets`. Users must use teleport where allowed (e.g. ROC with the Relay Chain).
type IsReserve = (
bridging::to_wococo::IsTrustedBridgedReserveLocationForConcreteAsset,
bridging::to_westend::IsTrustedBridgedReserveLocationForConcreteAsset,
bridging::to_rococo::IsTrustedBridgedReserveLocationForConcreteAsset,
);
type IsTeleporter = TrustedTeleporters;
@@ -624,8 +624,11 @@ impl xcm_executor::Config for XcmConfig {
XcmFeeToAccount<Self::AssetTransactor, AccountId, TreasuryAccount>,
>;
type MessageExporter = ();
type UniversalAliases =
(bridging::to_wococo::UniversalAliases, bridging::to_rococo::UniversalAliases);
type UniversalAliases = (
bridging::to_wococo::UniversalAliases,
bridging::to_rococo::UniversalAliases,
bridging::to_westend::UniversalAliases,
);
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
@@ -653,6 +656,9 @@ pub type XcmRouter = WithUniqueTopic<(
// Router which wraps and sends xcm to BridgeHub to be delivered to the Wococo
// GlobalConsensus
ToWococoXcmRouter,
// Router which wraps and sends xcm to BridgeHub to be delivered to the Westend
// GlobalConsensus
ToWestendXcmRouter,
// Router which wraps and sends xcm to BridgeHub to be delivered to the Rococo
// GlobalConsensus
ToRococoXcmRouter,
@@ -675,14 +681,7 @@ impl pallet_xcm::Config for Runtime {
type XcmExecuteFilter = Nothing;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Everything;
// Allow reserve based transfer to everywhere except for bridging, here we strictly check what
// assets are allowed.
type XcmReserveTransferFilter = (
LocationWithAssetFilters<WithParentsZeroOrOne, AllAssets>,
bridging::to_rococo::AllowedReserveTransferAssets,
bridging::to_wococo::AllowedReserveTransferAssets,
);
type XcmReserveTransferFilter = Everything;
type Weigher = WeightInfoBounds<
crate::weights::xcm::AssetHubRococoXcmWeight<RuntimeCall>,
RuntimeCall,
@@ -775,6 +774,7 @@ pub mod bridging {
pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> =
sp_std::vec::Vec::new().into_iter()
.chain(to_wococo::BridgeTable::get())
.chain(to_westend::BridgeTable::get())
.chain(to_rococo::BridgeTable::get())
.collect();
}
@@ -819,13 +819,6 @@ pub mod bridging {
)
];
/// Allowed assets for reserve transfer to `AssetHubWococo`.
pub AllowedReserveTransferAssetsToAssetHubWococo: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
// allow send only ROC
Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }),
// and nothing else
];
/// Universal aliases
pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter(
sp_std::vec![
@@ -852,12 +845,6 @@ pub mod bridging {
),
>;
/// Allows to reserve transfer assets to `AssetHubWococo`.
pub type AllowedReserveTransferAssets = LocationWithAssetFilters<
Equals<AssetHubWococo>,
AllowedReserveTransferAssetsToAssetHubWococo,
>;
impl Contains<RuntimeCall> for ToWococoXcmRouter {
fn contains(call: &RuntimeCall) -> bool {
matches!(
@@ -870,6 +857,82 @@ pub mod bridging {
}
}
pub mod to_westend {
use super::*;
parameter_types! {
pub SiblingBridgeHubWithBridgeHubWestendInstance: MultiLocation = MultiLocation::new(
1,
X2(
Parachain(SiblingBridgeHubParaId::get()),
PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)
)
);
pub const WestendNetwork: NetworkId = NetworkId::Westend;
pub AssetHubWestend: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(WestendNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)));
pub WndLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(WestendNetwork::get())));
pub WndFromAssetHubWestend: (MultiAssetFilter, MultiLocation) = (
Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }),
AssetHubWestend::get()
);
/// Set up exporters configuration.
/// `Option<MultiAsset>` represents static "base fee" which is used for total delivery fee calculation.
pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec![
NetworkExportTableItem::new(
WestendNetwork::get(),
Some(sp_std::vec![
AssetHubWestend::get().interior.split_global().expect("invalid configuration for AssetHubWestend").1,
]),
SiblingBridgeHub::get(),
// base delivery fee to local `BridgeHub`
Some((
XcmBridgeHubRouterFeeAssetId::get(),
bp_asset_hub_rococo::BridgeHubRococoBaseFeeInRocs::get(),
).into())
)
];
/// Universal aliases
pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter(
sp_std::vec![
(SiblingBridgeHubWithBridgeHubWestendInstance::get(), GlobalConsensus(WestendNetwork::get()))
]
);
}
impl Contains<(MultiLocation, Junction)> for UniversalAliases {
fn contains(alias: &(MultiLocation, Junction)) -> bool {
UniversalAliases::get().contains(alias)
}
}
/// Trusted reserve locations filter for `xcm_executor::Config::IsReserve`.
/// Locations from which the runtime accepts reserved assets.
pub type IsTrustedBridgedReserveLocationForConcreteAsset =
matching::IsTrustedBridgedReserveLocationForConcreteAsset<
UniversalLocation,
(
// allow receive WND from AssetHubWestend
xcm_builder::Case<WndFromAssetHubWestend>,
// and nothing else
),
>;
impl Contains<RuntimeCall> for ToWestendXcmRouter {
fn contains(call: &RuntimeCall) -> bool {
matches!(
call,
RuntimeCall::ToWestendXcmRouter(
pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. }
)
)
}
}
}
pub mod to_rococo {
use super::*;
@@ -908,13 +971,6 @@ pub mod bridging {
)
];
/// Allowed assets for reserve transfer to `AssetHubWococo`.
pub AllowedReserveTransferAssetsToAssetHubRococo: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
// allow send only WOC
Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) }),
// and nothing else
];
/// Universal aliases
pub UniversalAliases: BTreeSet<(MultiLocation, Junction)> = BTreeSet::from_iter(
sp_std::vec![
@@ -941,12 +997,6 @@ pub mod bridging {
),
>;
/// Allows to reserve transfer assets to `AssetHubRococo`.
pub type AllowedReserveTransferAssets = LocationWithAssetFilters<
Equals<AssetHubRococo>,
AllowedReserveTransferAssetsToAssetHubRococo,
>;
impl Contains<RuntimeCall> for ToRococoXcmRouter {
fn contains(call: &RuntimeCall) -> bool {
matches!(
@@ -967,15 +1017,17 @@ pub mod bridging {
impl BridgingBenchmarksHelper {
pub fn prepare_universal_alias() -> Option<(MultiLocation, Junction)> {
let alias =
to_wococo::UniversalAliases::get().into_iter().find_map(|(location, junction)| {
match to_wococo::SiblingBridgeHubWithBridgeHubWococoInstance::get()
.eq(&location)
{
true => Some((location, junction)),
false => None,
}
});
assert!(alias.is_some(), "we expect here BridgeHubRococo to Polkadot mapping at least");
to_westend::UniversalAliases::get()
.into_iter()
.find_map(|(location, junction)| {
match to_westend::SiblingBridgeHubWithBridgeHubWestendInstance::get()
.eq(&location)
{
true => Some((location, junction)),
false => None,
}
});
assert!(alias.is_some(), "we expect here BridgeHubRococo to Westend mapping at least");
Some(alias.unwrap())
}
}