From 85521e873f4b3023e7611711439e2e1b7d5fde41 Mon Sep 17 00:00:00 2001
From: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Date: Wed, 6 Nov 2024 17:46:28 -0300
Subject: [PATCH] XCM v5 (#4826)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

# Context

This PR aims to introduce XCMv5, for now it's in progress and will be
updated over time.
This branch will serve as a milestone branch for merging in all features
we want to add to XCM, roughly outlined
[here](https://github.com/polkadot-fellows/xcm-format/issues/60).
More features could be added.

## TODO
- [x] Migrate foreign assets from v3 to v4
- [x] Setup v5 skeleton
- [x] Remove XCMv2
- [x] https://github.com/paritytech/polkadot-sdk/pull/5390
- [x] https://github.com/paritytech/polkadot-sdk/pull/5585
- [x] https://github.com/paritytech/polkadot-sdk/pull/5420
- [x] https://github.com/paritytech/polkadot-sdk/pull/5876
- [x] https://github.com/paritytech/polkadot-sdk/pull/5971
- [x] https://github.com/paritytech/polkadot-sdk/pull/6148
- [x] https://github.com/paritytech/polkadot-sdk/pull/6228

Fixes #3434
Fixes https://github.com/paritytech/polkadot-sdk/issues/4190
Fixes https://github.com/paritytech/polkadot-sdk/issues/5209
Fixes https://github.com/paritytech/polkadot-sdk/issues/5241
Fixes https://github.com/paritytech/polkadot-sdk/issues/4284

---------

Signed-off-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Andrii <ndk@parity.io>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: Joseph Zhao <65984904+programskillforverification@users.noreply.github.com>
Co-authored-by: Nazar Mokrynskyi <nazar@mokrynskyi.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: command-bot <>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Serban Iorga <serban@parity.io>
---
 Cargo.lock                                    |    3 +
 .../modules/xcm-bridge-hub-router/src/mock.rs |    4 +-
 bridges/modules/xcm-bridge-hub/src/mock.rs    |    4 +-
 bridges/primitives/xcm-bridge-hub/src/lib.rs  |    3 +-
 .../pallets/inbound-queue/src/mock.rs         |    9 +-
 .../pallets/inbound-queue/src/test.rs         |    4 +-
 .../pallets/system/src/benchmarking.rs        |    2 +-
 bridges/snowbridge/pallets/system/src/lib.rs  |    4 +-
 .../primitives/core/src/location.rs           |   50 +-
 .../primitives/router/src/inbound/mod.rs      |    3 +-
 .../primitives/router/src/outbound/tests.rs   |   15 +-
 .../snowbridge/runtime/test-common/src/lib.rs |    9 +-
 cumulus/pallets/xcmp-queue/src/lib.rs         |    2 +-
 cumulus/pallets/xcmp-queue/src/tests.rs       |   23 +-
 .../assets/asset-hub-rococo/src/genesis.rs    |   18 +-
 .../assets/asset-hub-rococo/src/lib.rs        |    2 +-
 .../assets/asset-hub-westend/src/genesis.rs   |   12 +-
 .../assets/asset-hub-westend/src/lib.rs       |    2 +-
 .../bridges/bridge-hub-rococo/src/genesis.rs  |    4 +-
 .../bridges/bridge-hub-westend/src/genesis.rs |    7 +-
 .../bridges/bridge-hub-westend/src/lib.rs     |    2 +-
 .../parachains/testing/penpal/src/lib.rs      |    7 +-
 .../emulated/common/src/lib.rs                |   25 +-
 .../emulated/common/src/macros.rs             |  226 ++-
 .../emulated/common/src/xcm_helpers.rs        |    6 +-
 .../tests/assets/asset-hub-rococo/src/lib.rs  |    2 +-
 .../src/tests/claim_assets.rs                 |    8 +-
 .../src/tests/hybrid_transfers.rs             |   14 +-
 .../src/tests/reserve_transfer.rs             |    2 +-
 .../assets/asset-hub-rococo/src/tests/send.rs |    4 +-
 .../src/tests/set_xcm_versions.rs             |    2 +-
 .../asset-hub-rococo/src/tests/teleport.rs    |    2 +-
 .../asset-hub-rococo/src/tests/treasury.rs    |   35 +-
 .../src/tests/xcm_fee_estimation.rs           |   55 +-
 .../tests/assets/asset-hub-westend/Cargo.toml |    1 +
 .../tests/assets/asset-hub-westend/src/lib.rs |   11 +-
 .../src/tests/claim_assets.rs                 |    8 +-
 .../src/tests/fellowship_treasury.rs          |    7 +-
 .../src/tests/hybrid_transfers.rs             |   99 +-
 .../assets/asset-hub-westend/src/tests/mod.rs |   78 +
 .../src/tests/reserve_transfer.rs             |  298 +---
 .../asset-hub-westend/src/tests/send.rs       |    4 +-
 .../src/tests/set_asset_claimer.rs            |  154 ++
 .../src/tests/set_xcm_versions.rs             |    5 +-
 .../asset-hub-westend/src/tests/teleport.rs   |  123 +-
 .../asset-hub-westend/src/tests/transact.rs   |  246 +++
 .../asset-hub-westend/src/tests/treasury.rs   |    9 +-
 .../src/tests/xcm_fee_estimation.rs           |   51 +-
 .../bridges/bridge-hub-rococo/src/lib.rs      |    3 +-
 .../src/tests/asset_transfers.rs              |   14 +-
 .../src/tests/claim_assets.rs                 |    8 +-
 .../bridge-hub-rococo/src/tests/mod.rs        |   49 +-
 .../src/tests/register_bridged_assets.rs      |    4 +-
 .../bridge-hub-rococo/src/tests/send_xcm.rs   |   19 +-
 .../bridge-hub-rococo/src/tests/snowbridge.rs |   42 +-
 .../bridges/bridge-hub-westend/src/lib.rs     |   10 +-
 .../src/tests/asset_transfers.rs              |  323 +++-
 .../src/tests/claim_assets.rs                 |    8 +-
 .../bridge-hub-westend/src/tests/mod.rs       |  161 +-
 .../src/tests/register_bridged_assets.rs      |    4 +-
 .../bridge-hub-westend/src/tests/send_xcm.rs  |   19 +-
 .../src/tests/snowbridge.rs                   |   46 +-
 .../bridge-hub-westend/src/tests/transact.rs  |  248 +++
 .../src/tests/fellowship.rs                   |    1 -
 .../src/tests/fellowship_treasury.rs          |   31 +-
 .../tests/coretime/coretime-rococo/src/lib.rs |    2 +-
 .../coretime-rococo/src/tests/claim_assets.rs |    8 +-
 .../coretime/coretime-westend/src/lib.rs      |    2 +-
 .../src/tests/claim_assets.rs                 |    8 +-
 .../tests/people/people-rococo/src/lib.rs     |    2 +-
 .../people-rococo/src/tests/claim_assets.rs   |    8 +-
 .../tests/people/people-westend/src/lib.rs    |    2 +-
 .../people-westend/src/tests/claim_assets.rs  |    8 +-
 cumulus/parachains/pallets/ping/src/lib.rs    |    2 -
 .../assets/asset-hub-rococo/src/lib.rs        |   47 +-
 .../asset-hub-rococo/src/weights/xcm/mod.rs   |   40 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   65 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  139 +-
 .../assets/asset-hub-rococo/src/xcm_config.rs |   56 +-
 .../assets/asset-hub-rococo/tests/tests.rs    |   17 +-
 .../assets/asset-hub-westend/src/lib.rs       |   49 +-
 .../asset-hub-westend/src/weights/xcm/mod.rs  |   40 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   65 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  141 +-
 .../asset-hub-westend/src/xcm_config.rs       |   56 +-
 .../assets/asset-hub-westend/tests/tests.rs   |   75 +-
 .../runtimes/assets/common/src/lib.rs         |   32 +-
 .../runtimes/assets/common/src/matching.rs    |   23 +-
 .../assets/test-utils/src/test_cases.rs       |   24 +-
 .../test-utils/src/test_cases_over_bridge.rs  |    6 +-
 .../src/bridge_to_bulletin_config.rs          |    5 +-
 .../src/bridge_to_westend_config.rs           |   12 +-
 .../src/genesis_config_presets.rs             |    3 +-
 .../bridge-hubs/bridge-hub-rococo/src/lib.rs  |    7 +-
 .../bridge-hub-rococo/src/weights/xcm/mod.rs  |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   61 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  142 +-
 .../bridge-hub-rococo/src/xcm_config.rs       |    6 +-
 .../bridge-hub-rococo/tests/tests.rs          |   10 +-
 .../src/bridge_to_ethereum_config.rs          |   45 +
 .../src/bridge_to_rococo_config.rs            |   25 +-
 .../src/genesis_config_presets.rs             |    6 +-
 .../bridge-hubs/bridge-hub-westend/src/lib.rs |   13 +-
 .../bridge-hub-westend/src/weights/xcm/mod.rs |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   61 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  142 +-
 .../bridge-hub-westend/src/xcm_config.rs      |    6 +-
 .../bridge-hub-westend/tests/tests.rs         |    6 +-
 .../bridge-hubs/common/src/message_queue.rs   |    4 +-
 .../test-utils/src/test_cases/mod.rs          |   10 +-
 .../collectives-westend/src/xcm_config.rs     |    4 +-
 .../contracts-rococo/src/xcm_config.rs        |    4 +-
 .../coretime/coretime-rococo/src/coretime.rs  |    4 -
 .../coretime-rococo/src/weights/xcm/mod.rs    |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   59 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  130 +-
 .../coretime-rococo/src/xcm_config.rs         |    4 +-
 .../coretime/coretime-westend/src/coretime.rs |   16 -
 .../coretime-westend/src/weights/xcm/mod.rs   |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   59 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  130 +-
 .../coretime-westend/src/xcm_config.rs        |    4 +-
 .../glutton/glutton-westend/src/xcm_config.rs |    4 +-
 .../people-rococo/src/weights/xcm/mod.rs      |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   59 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  128 +-
 .../people/people-rococo/src/xcm_config.rs    |    4 +-
 .../people-westend/src/weights/xcm/mod.rs     |   37 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   59 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  130 +-
 .../people/people-westend/src/xcm_config.rs   |    4 +-
 .../parachains/runtimes/test-utils/src/lib.rs |   14 +-
 .../runtimes/test-utils/src/test_cases.rs     |   27 +-
 .../runtimes/testing/penpal/Cargo.toml        |    3 +
 .../runtimes/testing/penpal/src/lib.rs        |    8 +-
 .../runtimes/testing/penpal/src/xcm_config.rs |   25 +-
 .../testing/rococo-parachain/src/lib.rs       |    4 +-
 cumulus/xcm/xcm-emulator/src/lib.rs           |   29 +-
 polkadot/runtime/common/src/impls.rs          |   97 +-
 polkadot/runtime/common/src/xcm_sender.rs     |    2 +-
 .../parachains/src/coretime/migration.rs      |   29 +-
 .../runtime/parachains/src/coretime/mod.rs    |   25 +-
 polkadot/runtime/parachains/src/mock.rs       |   10 +-
 polkadot/runtime/rococo/src/impls.rs          |   18 +-
 polkadot/runtime/rococo/src/lib.rs            |    2 -
 .../runtime/rococo/src/weights/xcm/mod.rs     |   33 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   55 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  337 ++--
 polkadot/runtime/rococo/src/xcm_config.rs     |    4 +-
 polkadot/runtime/test-runtime/src/lib.rs      |    6 +-
 polkadot/runtime/westend/src/impls.rs         |   18 +-
 polkadot/runtime/westend/src/lib.rs           |    2 -
 .../runtime/westend/src/weights/xcm/mod.rs    |   35 +-
 .../xcm/pallet_xcm_benchmarks_fungible.rs     |   55 +-
 .../xcm/pallet_xcm_benchmarks_generic.rs      |  316 ++--
 polkadot/runtime/westend/src/xcm_config.rs    |    4 +-
 polkadot/xcm/Cargo.toml                       |    4 +-
 .../parachain/xcm_config.rs                   |    2 +-
 .../relay_token_transactor/relay_chain/mod.rs |    2 +-
 .../relay_chain/xcm_config.rs                 |    2 +-
 .../cookbook/relay_token_transactor/tests.rs  |   12 +-
 .../src/fungible/benchmarking.rs              |   29 +-
 .../src/generic/benchmarking.rs               |   33 +-
 polkadot/xcm/pallet-xcm/src/benchmarking.rs   |    4 +-
 polkadot/xcm/pallet-xcm/src/lib.rs            |    4 +-
 polkadot/xcm/pallet-xcm/src/tests/mod.rs      |   13 +-
 .../xcm/procedural/src/builder_pattern.rs     |  104 +-
 polkadot/xcm/procedural/src/lib.rs            |   30 +-
 polkadot/xcm/procedural/src/v2.rs             |  226 ---
 polkadot/xcm/procedural/src/v3.rs             |   30 -
 polkadot/xcm/procedural/src/v4.rs             |   41 +
 polkadot/xcm/procedural/src/v5.rs             |  198 ++
 .../badly_formatted_attribute.stderr          |    2 +-
 .../buy_execution_named_fields.rs             |   30 -
 .../buy_execution_named_fields.stderr         |    5 -
 .../builder_pattern/no_buy_execution.stderr   |    6 -
 .../builder_pattern/unexpected_attribute.rs   |   32 -
 .../unexpected_attribute.stderr               |    5 -
 polkadot/xcm/src/lib.rs                       |  326 ++--
 polkadot/xcm/src/tests.rs                     |  167 +-
 polkadot/xcm/src/v2/junction.rs               |  123 --
 polkadot/xcm/src/v2/mod.rs                    | 1222 -------------
 polkadot/xcm/src/v2/multiasset.rs             |  626 -------
 polkadot/xcm/src/v2/multilocation.rs          | 1105 ------------
 polkadot/xcm/src/v2/traits.rs                 |  363 ----
 polkadot/xcm/src/v3/junction.rs               |  125 --
 polkadot/xcm/src/v3/mod.rs                    |  202 +--
 polkadot/xcm/src/v3/multiasset.rs             |  136 +-
 polkadot/xcm/src/v3/multilocation.rs          |   44 +-
 polkadot/xcm/src/v3/traits.rs                 |   48 +-
 polkadot/xcm/src/v4/asset.rs                  |  103 +-
 polkadot/xcm/src/v4/junction.rs               |   47 +-
 polkadot/xcm/src/v4/location.rs               |   16 +-
 polkadot/xcm/src/v4/mod.rs                    |  237 ++-
 polkadot/xcm/src/v5/asset.rs                  | 1155 ++++++++++++
 polkadot/xcm/src/v5/junction.rs               |  321 ++++
 polkadot/xcm/src/v5/junctions.rs              |  723 ++++++++
 polkadot/xcm/src/v5/location.rs               |  755 ++++++++
 polkadot/xcm/src/v5/mod.rs                    | 1585 +++++++++++++++++
 polkadot/xcm/src/v5/traits.rs                 |  525 ++++++
 polkadot/xcm/xcm-builder/src/barriers.rs      |    1 +
 polkadot/xcm/xcm-builder/src/lib.rs           |    2 +-
 .../xcm/xcm-builder/src/origin_aliases.rs     |   33 +-
 .../xcm-builder/src/process_xcm_message.rs    |   24 +-
 polkadot/xcm/xcm-builder/src/tests/aliases.rs |  161 ++
 .../xcm/xcm-builder/src/tests/transacting.rs  |   16 +-
 polkadot/xcm/xcm-builder/src/weight.rs        |   30 +-
 .../xcm-executor/integration-tests/src/lib.rs |   10 +-
 polkadot/xcm/xcm-executor/src/lib.rs          |  559 ++++--
 .../src/tests/initiate_transfer.rs            |  106 ++
 polkadot/xcm/xcm-executor/src/tests/mock.rs   |  279 +++
 .../src/tests/mod.rs}                         |   23 +-
 .../xcm/xcm-executor/src/tests/pay_fees.rs    |  257 +++
 .../src/tests/set_asset_claimer.rs            |  138 ++
 .../xcm-executor/src/traits/fee_manager.rs    |    2 +
 .../xcm/xcm-executor/src/traits/weight.rs     |    2 +-
 polkadot/xcm/xcm-runtime-apis/tests/mock.rs   |    2 +-
 .../xcm/xcm-simulator/example/src/tests.rs    |    4 -
 prdoc/pr_4826.prdoc                           |   69 +
 prdoc/pr_5390.prdoc                           |   55 +
 prdoc/pr_5420.prdoc                           |   62 +
 prdoc/pr_5585.prdoc                           |   47 +
 prdoc/pr_5876.prdoc                           |   99 +
 prdoc/pr_5971.prdoc                           |   66 +
 prdoc/pr_6228.prdoc                           |   50 +
 .../src/migrations/v1/weights.rs              |    2 +-
 substrate/frame/system/src/lib.rs             |    4 +-
 227 files changed, 12140 insertions(+), 7048 deletions(-)
 create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs
 create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
 create mode 100644 cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
 delete mode 100644 polkadot/xcm/procedural/src/v2.rs
 create mode 100644 polkadot/xcm/procedural/src/v5.rs
 delete mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs
 delete mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr
 delete mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr
 delete mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs
 delete mode 100644 polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr
 delete mode 100644 polkadot/xcm/src/v2/junction.rs
 delete mode 100644 polkadot/xcm/src/v2/mod.rs
 delete mode 100644 polkadot/xcm/src/v2/multiasset.rs
 delete mode 100644 polkadot/xcm/src/v2/multilocation.rs
 delete mode 100644 polkadot/xcm/src/v2/traits.rs
 create mode 100644 polkadot/xcm/src/v5/asset.rs
 create mode 100644 polkadot/xcm/src/v5/junction.rs
 create mode 100644 polkadot/xcm/src/v5/junctions.rs
 create mode 100644 polkadot/xcm/src/v5/location.rs
 create mode 100644 polkadot/xcm/src/v5/mod.rs
 create mode 100644 polkadot/xcm/src/v5/traits.rs
 create mode 100644 polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs
 create mode 100644 polkadot/xcm/xcm-executor/src/tests/mock.rs
 rename polkadot/xcm/{procedural/tests/ui/builder_pattern/no_buy_execution.rs => xcm-executor/src/tests/mod.rs} (70%)
 create mode 100644 polkadot/xcm/xcm-executor/src/tests/pay_fees.rs
 create mode 100644 polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs
 create mode 100644 prdoc/pr_4826.prdoc
 create mode 100644 prdoc/pr_5390.prdoc
 create mode 100644 prdoc/pr_5420.prdoc
 create mode 100644 prdoc/pr_5585.prdoc
 create mode 100644 prdoc/pr_5876.prdoc
 create mode 100644 prdoc/pr_5971.prdoc
 create mode 100644 prdoc/pr_6228.prdoc

diff --git a/Cargo.lock b/Cargo.lock
index a824faedd6b..03350ff38f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -973,6 +973,7 @@ dependencies = [
  "sp-core 28.0.0",
  "sp-runtime 31.0.1",
  "staging-xcm",
+ "staging-xcm-builder",
  "staging-xcm-executor",
  "westend-system-emulated-network",
  "xcm-runtime-apis",
@@ -13642,6 +13643,7 @@ dependencies = [
  "primitive-types 0.12.2",
  "scale-info",
  "smallvec",
+ "snowbridge-router-primitives",
  "sp-api 26.0.0",
  "sp-block-builder",
  "sp-consensus-aura",
@@ -23628,6 +23630,7 @@ dependencies = [
  "bounded-collections",
  "derivative",
  "environmental",
+ "frame-support",
  "hex",
  "hex-literal",
  "impl-trait-for-tuples",
diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs
index bb265e1925a..09557288392 100644
--- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs
+++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs
@@ -141,8 +141,8 @@ impl InspectMessageQueues for TestToBridgeHubSender {
 				.iter()
 				.map(|(location, message)| {
 					(
-						VersionedLocation::V4(location.clone()),
-						vec![VersionedXcm::V4(message.clone())],
+						VersionedLocation::from(location.clone()),
+						vec![VersionedXcm::from(message.clone())],
 					)
 				})
 				.collect()
diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs
index 6511b9fc5b0..9f06b99ef6d 100644
--- a/bridges/modules/xcm-bridge-hub/src/mock.rs
+++ b/bridges/modules/xcm-bridge-hub/src/mock.rs
@@ -38,7 +38,7 @@ use sp_runtime::{
 	AccountId32, BuildStorage, StateVersion,
 };
 use sp_std::cell::RefCell;
-use xcm::prelude::*;
+use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*};
 use xcm_builder::{
 	AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds,
 	InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset,
@@ -160,7 +160,7 @@ parameter_types! {
 	pub BridgedRelayNetworkLocation: Location = (Parent, GlobalConsensus(BridgedRelayNetwork::get())).into();
 	pub BridgedRelativeDestination: InteriorLocation = [Parachain(BRIDGED_ASSET_HUB_ID)].into();
 	pub BridgedUniversalDestination: InteriorLocation = [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into();
-	pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo;
+	pub const NonBridgedRelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 
 	pub const BridgeDeposit: Balance = 100_000;
 
diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs
index 061e7a27506..63beb1bc304 100644
--- a/bridges/primitives/xcm-bridge-hub/src/lib.rs
+++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs
@@ -359,10 +359,11 @@ impl BridgeLocations {
 #[cfg(test)]
 mod tests {
 	use super::*;
+	use xcm::latest::ROCOCO_GENESIS_HASH;
 
 	const LOCAL_NETWORK: NetworkId = Kusama;
 	const REMOTE_NETWORK: NetworkId = Polkadot;
-	const UNREACHABLE_NETWORK: NetworkId = Rococo;
+	const UNREACHABLE_NETWORK: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	const SIBLING_PARACHAIN: u32 = 1000;
 	const LOCAL_BRIDGE_HUB: u32 = 1001;
 	const REMOTE_PARACHAIN: u32 = 2000;
diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs
index 3e67d5ab738..675d4b69159 100644
--- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs
+++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs
@@ -19,7 +19,10 @@ use sp_runtime::{
 	BuildStorage, FixedU128, MultiSignature,
 };
 use sp_std::{convert::From, default::Default};
-use xcm::{latest::SendXcm, prelude::*};
+use xcm::{
+	latest::{SendXcm, WESTEND_GENESIS_HASH},
+	prelude::*,
+};
 use xcm_executor::AssetsInHolding;
 
 use crate::{self as inbound_queue};
@@ -113,8 +116,8 @@ parameter_types! {
 	pub const InitialFund: u128 = 1_000_000_000_000;
 	pub const InboundQueuePalletInstance: u8 = 80;
 	pub UniversalLocation: InteriorLocation =
-		[GlobalConsensus(Westend), Parachain(1002)].into();
-	pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(Westend),Parachain(1000)]);
+		[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1002)].into();
+	pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),Parachain(1000)]);
 }
 
 #[cfg(feature = "runtime-benchmarks")]
diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs
index 41c38460aab..76d0b98e9eb 100644
--- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs
+++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs
@@ -40,8 +40,8 @@ fn test_submit_happy_path() {
 				.into(),
 			nonce: 1,
 			message_id: [
-				255, 125, 48, 71, 174, 185, 100, 26, 159, 43, 108, 6, 116, 218, 55, 155, 223, 143,
-				141, 22, 124, 110, 241, 18, 122, 217, 130, 29, 139, 76, 97, 201,
+				11, 25, 133, 51, 23, 68, 111, 211, 132, 94, 254, 17, 194, 252, 198, 233, 10, 193,
+				156, 93, 72, 140, 65, 69, 79, 155, 154, 28, 141, 166, 171, 255,
 			],
 			fee_burned: 110000000000,
 		}
diff --git a/bridges/snowbridge/pallets/system/src/benchmarking.rs b/bridges/snowbridge/pallets/system/src/benchmarking.rs
index 20798b7c349..939de9d40d1 100644
--- a/bridges/snowbridge/pallets/system/src/benchmarking.rs
+++ b/bridges/snowbridge/pallets/system/src/benchmarking.rs
@@ -169,7 +169,7 @@ mod benchmarks {
 		T::Token::mint_into(&caller, amount)?;
 
 		let relay_token_asset_id: Location = Location::parent();
-		let asset = Box::new(VersionedLocation::V4(relay_token_asset_id));
+		let asset = Box::new(VersionedLocation::from(relay_token_asset_id));
 		let asset_metadata = AssetMetadata {
 			name: "wnd".as_bytes().to_vec().try_into().unwrap(),
 			symbol: "wnd".as_bytes().to_vec().try_into().unwrap(),
diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs
index 1e8a788b7a5..eb3da095fe8 100644
--- a/bridges/snowbridge/pallets/system/src/lib.rs
+++ b/bridges/snowbridge/pallets/system/src/lib.rs
@@ -269,12 +269,12 @@ pub mod pallet {
 	/// Lookup table for foreign token ID to native location relative to ethereum
 	#[pallet::storage]
 	pub type ForeignToNativeId<T: Config> =
-		StorageMap<_, Blake2_128Concat, TokenId, xcm::v4::Location, OptionQuery>;
+		StorageMap<_, Blake2_128Concat, TokenId, xcm::v5::Location, OptionQuery>;
 
 	/// Lookup table for native location relative to ethereum to foreign token ID
 	#[pallet::storage]
 	pub type NativeToForeignId<T: Config> =
-		StorageMap<_, Blake2_128Concat, xcm::v4::Location, TokenId, OptionQuery>;
+		StorageMap<_, Blake2_128Concat, xcm::v5::Location, TokenId, OptionQuery>;
 
 	#[pallet::genesis_config]
 	#[derive(frame_support::DefaultNoBound)]
diff --git a/bridges/snowbridge/primitives/core/src/location.rs b/bridges/snowbridge/primitives/core/src/location.rs
index aad1c9ece05..f49a245c412 100644
--- a/bridges/snowbridge/primitives/core/src/location.rs
+++ b/bridges/snowbridge/primitives/core/src/location.rs
@@ -97,9 +97,12 @@ impl DescribeLocation for DescribeTokenTerminal {
 #[cfg(test)]
 mod tests {
 	use crate::TokenIdOf;
-	use xcm::prelude::{
-		GeneralIndex, GeneralKey, GlobalConsensus, Junction::*, Location, NetworkId::*,
-		PalletInstance, Parachain,
+	use xcm::{
+		latest::WESTEND_GENESIS_HASH,
+		prelude::{
+			GeneralIndex, GeneralKey, GlobalConsensus, Junction::*, Location, NetworkId::ByGenesis,
+			PalletInstance, Parachain,
+		},
 	};
 	use xcm_executor::traits::ConvertLocation;
 
@@ -108,17 +111,24 @@ mod tests {
 		let token_locations = [
 			// Relay Chain cases
 			// Relay Chain relative to Ethereum
-			Location::new(1, [GlobalConsensus(Westend)]),
+			Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]),
 			// Parachain cases
 			// Parachain relative to Ethereum
-			Location::new(1, [GlobalConsensus(Westend), Parachain(2000)]),
+			Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000)]),
 			// Parachain general index
-			Location::new(1, [GlobalConsensus(Westend), Parachain(2000), GeneralIndex(1)]),
+			Location::new(
+				1,
+				[
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+					Parachain(2000),
+					GeneralIndex(1),
+				],
+			),
 			// Parachain general key
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					GeneralKey { length: 32, data: [0; 32] },
 				],
@@ -127,7 +137,7 @@ mod tests {
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					AccountKey20 { network: None, key: [0; 20] },
 				],
@@ -136,24 +146,36 @@ mod tests {
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					AccountId32 { network: None, id: [0; 32] },
 				],
 			),
 			// Parchain Pallet instance cases
 			// Parachain pallet instance
-			Location::new(1, [GlobalConsensus(Westend), Parachain(2000), PalletInstance(8)]),
+			Location::new(
+				1,
+				[
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+					Parachain(2000),
+					PalletInstance(8),
+				],
+			),
 			// Parachain Pallet general index
 			Location::new(
 				1,
-				[GlobalConsensus(Westend), Parachain(2000), PalletInstance(8), GeneralIndex(1)],
+				[
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+					Parachain(2000),
+					PalletInstance(8),
+					GeneralIndex(1),
+				],
 			),
 			// Parachain Pallet general key
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					PalletInstance(8),
 					GeneralKey { length: 32, data: [0; 32] },
@@ -163,7 +185,7 @@ mod tests {
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					PalletInstance(8),
 					AccountKey20 { network: None, key: [0; 20] },
@@ -173,7 +195,7 @@ mod tests {
 			Location::new(
 				1,
 				[
-					GlobalConsensus(Westend),
+					GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 					Parachain(2000),
 					PalletInstance(8),
 					AccountId32 { network: None, id: [0; 32] },
diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
index 357f77f831c..e03560f66e2 100644
--- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs
+++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
@@ -7,7 +7,7 @@ mod tests;
 
 use codec::{Decode, Encode};
 use core::marker::PhantomData;
-use frame_support::{traits::tokens::Balance as BalanceT, weights::Weight, PalletError};
+use frame_support::{traits::tokens::Balance as BalanceT, PalletError};
 use scale_info::TypeInfo;
 use snowbridge_core::TokenId;
 use sp_core::{Get, RuntimeDebug, H160, H256};
@@ -279,7 +279,6 @@ where
 			// Call create_asset on foreign assets pallet.
 			Transact {
 				origin_kind: OriginKind::Xcm,
-				require_weight_at_most: Weight::from_parts(400_000_000, 8_000),
 				call: (
 					create_call_index,
 					asset_id,
diff --git a/bridges/snowbridge/primitives/router/src/outbound/tests.rs b/bridges/snowbridge/primitives/router/src/outbound/tests.rs
index 8bd3fa24df5..44f81ce31b3 100644
--- a/bridges/snowbridge/primitives/router/src/outbound/tests.rs
+++ b/bridges/snowbridge/primitives/router/src/outbound/tests.rs
@@ -5,7 +5,10 @@ use snowbridge_core::{
 	AgentIdOf,
 };
 use sp_std::default::Default;
-use xcm::prelude::SendError as XcmSendError;
+use xcm::{
+	latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH},
+	prelude::SendError as XcmSendError,
+};
 
 use super::*;
 
@@ -61,7 +64,7 @@ impl SendMessageFeeProvider for MockErrOutboundQueue {
 pub struct MockTokenIdConvert;
 impl MaybeEquivalence<TokenId, Location> for MockTokenIdConvert {
 	fn convert(_id: &TokenId) -> Option<Location> {
-		Some(Location::new(1, [GlobalConsensus(Westend)]))
+		Some(Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]))
 	}
 	fn convert_back(_loc: &Location) -> Option<TokenId> {
 		None
@@ -1109,7 +1112,7 @@ fn xcm_converter_transfer_native_token_success() {
 	let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000");
 
 	let amount = 1000000;
-	let asset_location = Location::new(1, [GlobalConsensus(Westend)]);
+	let asset_location = Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]);
 	let token_id = TokenIdOf::convert_location(&asset_location).unwrap();
 
 	let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into();
@@ -1142,7 +1145,8 @@ fn xcm_converter_transfer_native_token_with_invalid_location_will_fail() {
 
 	let amount = 1000000;
 	// Invalid asset location from a different consensus
-	let asset_location = Location { parents: 2, interior: [GlobalConsensus(Rococo)].into() };
+	let asset_location =
+		Location { parents: 2, interior: [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))].into() };
 
 	let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into();
 	let filter: AssetFilter = assets.clone().into();
@@ -1221,7 +1225,8 @@ fn exporter_validate_with_invalid_universal_source_does_not_alter_universal_sour
 	let network = BridgedNetwork::get();
 	let destination: InteriorLocation = Here.into();
 
-	let universal_source: InteriorLocation = [GlobalConsensus(Westend), Parachain(1000)].into();
+	let universal_source: InteriorLocation =
+		[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000)].into();
 
 	let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000");
 	let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000");
diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs
index b157ad4356b..dca5062ab31 100644
--- a/bridges/snowbridge/runtime/test-common/src/lib.rs
+++ b/bridges/snowbridge/runtime/test-common/src/lib.rs
@@ -15,10 +15,7 @@ use snowbridge_pallet_ethereum_client_fixtures::*;
 use sp_core::{Get, H160, U256};
 use sp_keyring::AccountKeyring::*;
 use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating};
-use xcm::{
-	latest::prelude::*,
-	v3::Error::{self, Barrier},
-};
+use xcm::latest::prelude::*;
 use xcm_executor::XcmExecutor;
 
 type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
@@ -374,7 +371,7 @@ pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
 				Weight::zero(),
 			);
 			// check error is barrier
-			assert_err!(outcome.ensure_complete(), Barrier);
+			assert_err!(outcome.ensure_complete(), XcmError::Barrier);
 		});
 }
 
@@ -388,7 +385,7 @@ pub fn send_transfer_token_message_failure<Runtime, XcmConfig>(
 	weth_contract_address: H160,
 	destination_address: H160,
 	fee_amount: u128,
-	expected_error: Error,
+	expected_error: XcmError,
 ) where
 	Runtime: frame_system::Config
 		+ pallet_balances::Config
diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs
index 6bb7395f655..91f71558b54 100644
--- a/cumulus/pallets/xcmp-queue/src/lib.rs
+++ b/cumulus/pallets/xcmp-queue/src/lib.rs
@@ -1036,7 +1036,7 @@ impl<T: Config> InspectMessageQueues for Pallet<T> {
 				}
 
 				(
-					VersionedLocation::V4((Parent, Parachain(para_id.into())).into()),
+					VersionedLocation::from(Location::new(1, Parachain(para_id.into()))),
 					decoded_messages,
 				)
 			})
diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs
index 5b02baf2310..bf042f15ccc 100644
--- a/cumulus/pallets/xcmp-queue/src/tests.rs
+++ b/cumulus/pallets/xcmp-queue/src/tests.rs
@@ -456,7 +456,7 @@ fn send_xcm_nested_works() {
 			XcmpQueue::take_outbound_messages(usize::MAX),
 			vec![(
 				HRMP_PARA_ID.into(),
-				(XcmpMessageFormat::ConcatenatedVersionedXcm, VersionedXcm::V4(good.clone()))
+				(XcmpMessageFormat::ConcatenatedVersionedXcm, VersionedXcm::from(good.clone()))
 					.encode(),
 			)]
 		);
@@ -512,7 +512,7 @@ fn hrmp_signals_are_prioritized() {
 		// Without a signal we get the messages in order:
 		let mut expected_msg = XcmpMessageFormat::ConcatenatedVersionedXcm.encode();
 		for _ in 0..31 {
-			expected_msg.extend(VersionedXcm::V4(message.clone()).encode());
+			expected_msg.extend(VersionedXcm::from(message.clone()).encode());
 		}
 
 		hypothetically!({
@@ -539,6 +539,7 @@ fn maybe_double_encoded_versioned_xcm_works() {
 	// pre conditions
 	assert_eq!(VersionedXcm::<()>::V3(Default::default()).encode(), &[3, 0]);
 	assert_eq!(VersionedXcm::<()>::V4(Default::default()).encode(), &[4, 0]);
+	assert_eq!(VersionedXcm::<()>::V5(Default::default()).encode(), &[5, 0]);
 }
 
 // Now also testing a page instead of just concat messages.
@@ -597,7 +598,7 @@ fn take_first_concatenated_xcm_good_recursion_depth_works() {
 	for _ in 0..MAX_XCM_DECODE_DEPTH - 1 {
 		good = Xcm(vec![SetAppendix(good)]);
 	}
-	let good = VersionedXcm::V4(good);
+	let good = VersionedXcm::from(good);
 
 	let page = good.encode();
 	assert_ok!(XcmpQueue::take_first_concatenated_xcm(&mut &page[..], &mut WeightMeter::new()));
@@ -610,7 +611,7 @@ fn take_first_concatenated_xcm_good_bad_depth_errors() {
 	for _ in 0..MAX_XCM_DECODE_DEPTH {
 		bad = Xcm(vec![SetAppendix(bad)]);
 	}
-	let bad = VersionedXcm::V4(bad);
+	let bad = VersionedXcm::from(bad);
 
 	let page = bad.encode();
 	assert_err!(
@@ -872,18 +873,18 @@ fn get_messages_works() {
 			queued_messages,
 			vec![
 				(
-					VersionedLocation::V4(other_destination),
+					VersionedLocation::from(other_destination),
 					vec![
-						VersionedXcm::V4(Xcm(vec![ClearOrigin])),
-						VersionedXcm::V4(Xcm(vec![ClearOrigin])),
+						VersionedXcm::from(Xcm(vec![ClearOrigin])),
+						VersionedXcm::from(Xcm(vec![ClearOrigin])),
 					],
 				),
 				(
-					VersionedLocation::V4(destination),
+					VersionedLocation::from(destination),
 					vec![
-						VersionedXcm::V4(Xcm(vec![ClearOrigin])),
-						VersionedXcm::V4(Xcm(vec![ClearOrigin])),
-						VersionedXcm::V4(Xcm(vec![ClearOrigin])),
+						VersionedXcm::from(Xcm(vec![ClearOrigin])),
+						VersionedXcm::from(Xcm(vec![ClearOrigin])),
+						VersionedXcm::from(Xcm(vec![ClearOrigin])),
 					],
 				),
 			],
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs
index 606d04060b6..3ffb9a704b4 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs
@@ -20,8 +20,9 @@ use sp_keyring::Sr25519Keyring as Keyring;
 
 // Cumulus
 use emulated_integration_tests_common::{
-	accounts, build_genesis_storage, collators, PenpalSiblingSovereignAccount,
-	PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID,
+	accounts, build_genesis_storage, collators, PenpalASiblingSovereignAccount,
+	PenpalATeleportableAssetLocation, PenpalBSiblingSovereignAccount,
+	PenpalBTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID,
 };
 use parachains_common::{AccountId, Balance};
 
@@ -77,10 +78,17 @@ pub fn genesis() -> Storage {
 		},
 		foreign_assets: asset_hub_rococo_runtime::ForeignAssetsConfig {
 			assets: vec![
-				// Penpal's teleportable asset representation
+				// PenpalA's teleportable asset representation
 				(
-					PenpalTeleportableAssetLocation::get(),
-					PenpalSiblingSovereignAccount::get(),
+					PenpalATeleportableAssetLocation::get(),
+					PenpalASiblingSovereignAccount::get(),
+					false,
+					ED,
+				),
+				// PenpalB's teleportable asset representation
+				(
+					PenpalBTeleportableAssetLocation::get(),
+					PenpalBSiblingSovereignAccount::get(),
 					false,
 					ED,
 				),
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs
index 75b61d6a4cd..1a075b9fe6b 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs
@@ -59,7 +59,7 @@ impl_accounts_helpers_for_parachain!(AssetHubRococo);
 impl_assert_events_helpers_for_parachain!(AssetHubRococo);
 impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo);
 impl_assets_helpers_for_parachain!(AssetHubRococo);
-impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v4::Location);
+impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v5::Location);
 impl_xcm_helpers_for_parachain!(AssetHubRococo);
 impl_bridge_helpers_for_chain!(
 	AssetHubRococo,
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs
index 30e7279a383..ef7997322da 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs
@@ -20,9 +20,9 @@ use sp_keyring::Sr25519Keyring as Keyring;
 
 // Cumulus
 use emulated_integration_tests_common::{
-	accounts, build_genesis_storage, collators, PenpalBSiblingSovereignAccount,
-	PenpalBTeleportableAssetLocation, PenpalSiblingSovereignAccount,
-	PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID,
+	accounts, build_genesis_storage, collators, PenpalASiblingSovereignAccount,
+	PenpalATeleportableAssetLocation, PenpalBSiblingSovereignAccount,
+	PenpalBTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID,
 };
 use parachains_common::{AccountId, Balance};
 
@@ -75,10 +75,10 @@ pub fn genesis() -> Storage {
 		},
 		foreign_assets: asset_hub_westend_runtime::ForeignAssetsConfig {
 			assets: vec![
-				// Penpal's teleportable asset representation
+				// PenpalA's teleportable asset representation
 				(
-					PenpalTeleportableAssetLocation::get(),
-					PenpalSiblingSovereignAccount::get(),
+					PenpalATeleportableAssetLocation::get(),
+					PenpalASiblingSovereignAccount::get(),
 					false,
 					ED,
 				),
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs
index c44f4b010c0..3e240ed6748 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs
@@ -59,7 +59,7 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend);
 impl_assert_events_helpers_for_parachain!(AssetHubWestend);
 impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend);
 impl_assets_helpers_for_parachain!(AssetHubWestend);
-impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v4::Location);
+impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v5::Location);
 impl_xcm_helpers_for_parachain!(AssetHubWestend);
 impl_bridge_helpers_for_chain!(
 	AssetHubWestend,
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs
index 0268a6a7a1b..575017f88bb 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs
@@ -22,7 +22,7 @@ use emulated_integration_tests_common::{
 	accounts, build_genesis_storage, collators, SAFE_XCM_VERSION,
 };
 use parachains_common::Balance;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 
 pub const ASSETHUB_PARA_ID: u32 = 1000;
 pub const PARA_ID: u32 = 1013;
@@ -73,7 +73,7 @@ pub fn genesis() -> Storage {
 				// open AHR -> AHW bridge
 				(
 					Location::new(1, [Parachain(1000)]),
-					Junctions::from([Westend.into(), Parachain(1000)]),
+					Junctions::from([ByGenesis(WESTEND_GENESIS_HASH).into(), Parachain(1000)]),
 					Some(bp_messages::LegacyLaneId([0, 0, 0, 2])),
 				),
 			],
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs
index f72eaa30026..eb4623084f8 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs
@@ -22,7 +22,7 @@ use emulated_integration_tests_common::{
 	accounts, build_genesis_storage, collators, SAFE_XCM_VERSION,
 };
 use parachains_common::Balance;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 
 pub const PARA_ID: u32 = 1002;
 pub const ASSETHUB_PARA_ID: u32 = 1000;
@@ -73,7 +73,10 @@ pub fn genesis() -> Storage {
 				// open AHW -> AHR bridge
 				(
 					Location::new(1, [Parachain(1000)]),
-					Junctions::from([Rococo.into(), Parachain(1000)]),
+					Junctions::from([
+						NetworkId::ByGenesis(ROCOCO_GENESIS_HASH).into(),
+						Parachain(1000),
+					]),
 					Some(bp_messages::LegacyLaneId([0, 0, 0, 2])),
 				),
 			],
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs
index e7a28ebf4a4..b548e3b7e64 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs
@@ -16,7 +16,7 @@
 pub mod genesis;
 
 pub use bridge_hub_westend_runtime::{
-	xcm_config::XcmConfig as BridgeHubWestendXcmConfig,
+	self, xcm_config::XcmConfig as BridgeHubWestendXcmConfig,
 	ExistentialDeposit as BridgeHubWestendExistentialDeposit,
 };
 
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs
index 92dfa30f2e8..f5642dbb0da 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs
@@ -31,6 +31,9 @@ use emulated_integration_tests_common::{
 	xcm_emulator::decl_test_parachains,
 };
 
+// Polkadot
+use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
+
 // Penpal Parachain declaration
 decl_test_parachains! {
 	pub struct PenpalA {
@@ -39,7 +42,7 @@ decl_test_parachains! {
 			penpal_runtime::AuraExt::on_initialize(1);
 			frame_support::assert_ok!(penpal_runtime::System::set_storage(
 				penpal_runtime::RuntimeOrigin::root(),
-				vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Rococo.encode())],
+				vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::ByGenesis(ROCOCO_GENESIS_HASH).encode())],
 			));
 		},
 		runtime = penpal_runtime,
@@ -63,7 +66,7 @@ decl_test_parachains! {
 			penpal_runtime::AuraExt::on_initialize(1);
 			frame_support::assert_ok!(penpal_runtime::System::set_storage(
 				penpal_runtime::RuntimeOrigin::root(),
-				vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Westend.encode())],
+				vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::ByGenesis(WESTEND_GENESIS_HASH).encode())],
 			));
 		},
 		runtime = penpal_runtime,
diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs
index 07fde111d3d..e2757f8b9a3 100644
--- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs
@@ -41,6 +41,7 @@ use polkadot_primitives::{AssignmentId, ValidatorId};
 pub const XCM_V2: u32 = 2;
 pub const XCM_V3: u32 = 3;
 pub const XCM_V4: u32 = 4;
+pub const XCM_V5: u32 = 5;
 pub const REF_TIME_THRESHOLD: u64 = 33;
 pub const PROOF_SIZE_THRESHOLD: u64 = 33;
 
@@ -55,26 +56,26 @@ pub const TELEPORTABLE_ASSET_ID: u32 = 2;
 // USDT registered on AH as (trust-backed) Asset and reserve-transferred between Parachain and AH
 pub const USDT_ID: u32 = 1984;
 
-pub const PENPAL_ID: u32 = 2000;
+pub const PENPAL_A_ID: u32 = 2000;
 pub const PENPAL_B_ID: u32 = 2001;
 pub const ASSETS_PALLET_ID: u8 = 50;
 
 parameter_types! {
-	pub PenpalTeleportableAssetLocation: xcm::v4::Location
-		= xcm::v4::Location::new(1, [
-				xcm::v4::Junction::Parachain(PENPAL_ID),
-				xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID),
-				xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()),
+	pub PenpalATeleportableAssetLocation: xcm::v5::Location
+		= xcm::v5::Location::new(1, [
+				xcm::v5::Junction::Parachain(PENPAL_A_ID),
+				xcm::v5::Junction::PalletInstance(ASSETS_PALLET_ID),
+				xcm::v5::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()),
 			]
 		);
-	pub PenpalSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating();
-	pub PenpalBTeleportableAssetLocation: xcm::v4::Location
-		= xcm::v4::Location::new(1, [
-				xcm::v4::Junction::Parachain(PENPAL_B_ID),
-				xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID),
-				xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()),
+	pub PenpalBTeleportableAssetLocation: xcm::v5::Location
+		= xcm::v5::Location::new(1, [
+				xcm::v5::Junction::Parachain(PENPAL_B_ID),
+				xcm::v5::Junction::PalletInstance(ASSETS_PALLET_ID),
+				xcm::v5::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()),
 			]
 		);
+	pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(PENPAL_A_ID).into_account_truncating();
 	pub PenpalBSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_B_ID).into_account_truncating();
 }
 
diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs
index 3ff5ed388a3..b776cafb254 100644
--- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs
+++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs
@@ -404,6 +404,230 @@ macro_rules! test_chain_can_claim_assets {
 	};
 }
 
+#[macro_export]
+macro_rules! test_can_estimate_and_pay_exact_fees {
+	( $sender_para:ty, $asset_hub:ty, $receiver_para:ty, ($asset_id:expr, $amount:expr), $owner_prefix:ty ) => {
+		$crate::macros::paste::paste! {
+			// We first define the call we'll use throughout the test.
+			fn get_call(
+				estimated_local_fees: impl Into<Asset>,
+				estimated_intermediate_fees: impl Into<Asset>,
+				estimated_remote_fees: impl Into<Asset>,
+			) -> <$sender_para as Chain>::RuntimeCall {
+				type RuntimeCall = <$sender_para as Chain>::RuntimeCall;
+
+				let beneficiary = [<$receiver_para Receiver>]::get();
+				let xcm_in_destination = Xcm::<()>::builder_unsafe()
+					.pay_fees(estimated_remote_fees)
+					.deposit_asset(AllCounted(1), beneficiary)
+					.build();
+				let ah_to_receiver = $asset_hub::sibling_location_of($receiver_para::para_id());
+				let xcm_in_reserve = Xcm::<()>::builder_unsafe()
+					.pay_fees(estimated_intermediate_fees)
+					.deposit_reserve_asset(
+						AllCounted(1),
+						ah_to_receiver,
+						xcm_in_destination,
+					)
+					.build();
+				let sender_to_ah = $sender_para::sibling_location_of($asset_hub::para_id());
+				let local_xcm = Xcm::<<$sender_para as Chain>::RuntimeCall>::builder()
+					.withdraw_asset(($asset_id, $amount))
+					.pay_fees(estimated_local_fees)
+					.initiate_reserve_withdraw(AllCounted(1), sender_to_ah, xcm_in_reserve)
+					.build();
+
+				RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute {
+					message: bx!(VersionedXcm::from(local_xcm)),
+					max_weight: Weight::from_parts(10_000_000_000, 500_000),
+				})
+			}
+
+			let destination = $sender_para::sibling_location_of($receiver_para::para_id());
+			let sender = [<$sender_para Sender>]::get();
+			let sender_as_seen_by_ah = $asset_hub::sibling_location_of($sender_para::para_id());
+			let sov_of_sender_on_ah = $asset_hub::sovereign_account_id_of(sender_as_seen_by_ah.clone());
+			let asset_owner = [<$owner_prefix AssetOwner>]::get();
+
+			// Fund parachain's sender account.
+			$sender_para::mint_foreign_asset(
+				<$sender_para as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
+				$asset_id.clone().into(),
+				sender.clone(),
+				$amount * 2,
+			);
+
+			// Fund the parachain origin's SA on Asset Hub with the native tokens.
+			$asset_hub::fund_accounts(vec![(sov_of_sender_on_ah.clone(), $amount * 2)]);
+
+			let beneficiary_id = [<$receiver_para Receiver>]::get();
+
+			let test_args = TestContext {
+				sender: sender.clone(),
+				receiver: beneficiary_id.clone(),
+				args: TestArgs::new_para(
+					destination,
+					beneficiary_id.clone(),
+					$amount,
+					($asset_id, $amount).into(),
+					None,
+					0,
+				),
+			};
+			let mut test = ParaToParaThroughAHTest::new(test_args);
+
+			// We get these from the closure.
+			let mut local_execution_fees = 0;
+			let mut local_delivery_fees = 0;
+			let mut remote_message = VersionedXcm::from(Xcm::<()>(Vec::new()));
+			<$sender_para as TestExt>::execute_with(|| {
+				type Runtime = <$sender_para as Chain>::Runtime;
+				type OriginCaller = <$sender_para as Chain>::OriginCaller;
+
+				let call = get_call(
+					(Parent, 100_000_000_000u128),
+					(Parent, 100_000_000_000u128),
+					(Parent, 100_000_000_000u128),
+				);
+				let origin = OriginCaller::system(RawOrigin::Signed(sender.clone()));
+				let result = Runtime::dry_run_call(origin, call).unwrap();
+				let local_xcm = result.local_xcm.unwrap().clone();
+				let local_xcm_weight = Runtime::query_xcm_weight(local_xcm).unwrap();
+				local_execution_fees = Runtime::query_weight_to_asset_fee(
+					local_xcm_weight,
+					VersionedAssetId::from(AssetId(Location::parent())),
+				)
+				.unwrap();
+				// We filter the result to get only the messages we are interested in.
+				let (destination_to_query, messages_to_query) = &result
+					.forwarded_xcms
+					.iter()
+					.find(|(destination, _)| {
+						*destination == VersionedLocation::from(Location::new(1, [Parachain(1000)]))
+					})
+					.unwrap();
+				assert_eq!(messages_to_query.len(), 1);
+				remote_message = messages_to_query[0].clone();
+				let delivery_fees =
+					Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone())
+						.unwrap();
+				local_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees);
+			});
+
+			// These are set in the AssetHub closure.
+			let mut intermediate_execution_fees = 0;
+			let mut intermediate_delivery_fees = 0;
+			let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new()));
+			<$asset_hub as TestExt>::execute_with(|| {
+				type Runtime = <$asset_hub as Chain>::Runtime;
+				type RuntimeCall = <$asset_hub as Chain>::RuntimeCall;
+
+				// First we get the execution fees.
+				let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap();
+				intermediate_execution_fees = Runtime::query_weight_to_asset_fee(
+					weight,
+					VersionedAssetId::from(AssetId(Location::new(1, []))),
+				)
+				.unwrap();
+
+				// We have to do this to turn `VersionedXcm<()>` into `VersionedXcm<RuntimeCall>`.
+				let xcm_program =
+					VersionedXcm::from(Xcm::<RuntimeCall>::from(remote_message.clone().try_into().unwrap()));
+
+				// Now we get the delivery fees to the final destination.
+				let result =
+					Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap();
+				let (destination_to_query, messages_to_query) = &result
+					.forwarded_xcms
+					.iter()
+					.find(|(destination, _)| {
+						*destination == VersionedLocation::from(Location::new(1, [Parachain(2001)]))
+					})
+					.unwrap();
+				// There's actually two messages here.
+				// One created when the message we sent from `$sender_para` arrived and was executed.
+				// The second one when we dry-run the xcm.
+				// We could've gotten the message from the queue without having to dry-run, but
+				// offchain applications would have to dry-run, so we do it here as well.
+				intermediate_remote_message = messages_to_query[0].clone();
+				let delivery_fees = Runtime::query_delivery_fees(
+					destination_to_query.clone(),
+					intermediate_remote_message.clone(),
+				)
+				.unwrap();
+				intermediate_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees);
+			});
+
+			// Get the final execution fees in the destination.
+			let mut final_execution_fees = 0;
+			<$receiver_para as TestExt>::execute_with(|| {
+				type Runtime = <$sender_para as Chain>::Runtime;
+
+				let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap();
+				final_execution_fees =
+					Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(Location::parent())))
+						.unwrap();
+			});
+
+			// Dry-running is done.
+			$sender_para::reset_ext();
+			$asset_hub::reset_ext();
+			$receiver_para::reset_ext();
+
+			// Fund accounts again.
+			$sender_para::mint_foreign_asset(
+				<$sender_para as Chain>::RuntimeOrigin::signed(asset_owner),
+				$asset_id.clone().into(),
+				sender.clone(),
+				$amount * 2,
+			);
+			$asset_hub::fund_accounts(vec![(sov_of_sender_on_ah, $amount * 2)]);
+
+			// Actually run the extrinsic.
+			let sender_assets_before = $sender_para::execute_with(|| {
+				type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets;
+				<ForeignAssets as Inspect<_>>::balance($asset_id.clone().into(), &sender)
+			});
+			let receiver_assets_before = $receiver_para::execute_with(|| {
+				type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets;
+				<ForeignAssets as Inspect<_>>::balance($asset_id.clone().into(), &beneficiary_id)
+			});
+
+			test.set_assertion::<$sender_para>(sender_assertions);
+			test.set_assertion::<$asset_hub>(hop_assertions);
+			test.set_assertion::<$receiver_para>(receiver_assertions);
+			let call = get_call(
+				(Parent, local_execution_fees + local_delivery_fees),
+				(Parent, intermediate_execution_fees + intermediate_delivery_fees),
+				(Parent, final_execution_fees),
+			);
+			test.set_call(call);
+			test.assert();
+
+			let sender_assets_after = $sender_para::execute_with(|| {
+				type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets;
+				<ForeignAssets as Inspect<_>>::balance($asset_id.clone().into(), &sender)
+			});
+			let receiver_assets_after = $receiver_para::execute_with(|| {
+				type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets;
+				<ForeignAssets as Inspect<_>>::balance($asset_id.into(), &beneficiary_id)
+			});
+
+			// We know the exact fees on every hop.
+			assert_eq!(sender_assets_after, sender_assets_before - $amount);
+			assert_eq!(
+				receiver_assets_after,
+				receiver_assets_before + $amount -
+					local_execution_fees -
+					local_delivery_fees -
+					intermediate_execution_fees -
+					intermediate_delivery_fees -
+					final_execution_fees
+			);
+		}
+	};
+}
+
 #[macro_export]
 macro_rules! test_dry_run_transfer_across_pk_bridge {
 	( $sender_asset_hub:ty, $sender_bridge_hub:ty, $destination:expr ) => {
@@ -474,7 +698,7 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub {
 				));
 
 				type Runtime = <$asset_hub as Chain>::Runtime;
-				let acceptable_payment_assets = Runtime::query_acceptable_payment_assets(4).unwrap();
+				let acceptable_payment_assets = Runtime::query_acceptable_payment_assets(XCM_VERSION).unwrap();
 				assert_eq!(acceptable_payment_assets, vec![
 					VersionedAssetId::from(AssetId(wnd.clone())),
 					VersionedAssetId::from(AssetId(usdt.clone())),
diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
index 7a289a3f1ac..9125c976525 100644
--- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
+++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs
@@ -27,12 +27,11 @@ pub fn xcm_transact_paid_execution(
 	beneficiary: AccountId,
 ) -> VersionedXcm<()> {
 	let weight_limit = WeightLimit::Unlimited;
-	let require_weight_at_most = Weight::from_parts(1000000000, 200000);
 
 	VersionedXcm::from(Xcm(vec![
 		WithdrawAsset(fees.clone().into()),
 		BuyExecution { fees, weight_limit },
-		Transact { require_weight_at_most, origin_kind, call },
+		Transact { origin_kind, call },
 		RefundSurplus,
 		DepositAsset {
 			assets: All.into(),
@@ -50,12 +49,11 @@ pub fn xcm_transact_unpaid_execution(
 	origin_kind: OriginKind,
 ) -> VersionedXcm<()> {
 	let weight_limit = WeightLimit::Unlimited;
-	let require_weight_at_most = Weight::from_parts(1000000000, 200000);
 	let check_origin = None;
 
 	VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit, check_origin },
-		Transact { require_weight_at_most, origin_kind, call },
+		Transact { origin_kind, call },
 	]))
 }
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs
index 1184b5fd7c4..f3a1b3f5bfa 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs
@@ -27,8 +27,8 @@ mod imports {
 
 	// Polkadot
 	pub use xcm::{
+		latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH},
 		prelude::{AccountId32 as AccountId32Junction, *},
-		v3,
 	};
 	pub use xcm_executor::traits::TransferType;
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs
index 99b31aba4be..52a20c00c27 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = AssetHubRococoExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount);
+	test_chain_can_claim_assets!(
+		AssetHubRococo,
+		RuntimeCall,
+		NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs
index 7bb25d7cec6..baec7d20f41 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs
@@ -163,7 +163,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() {
 	// Foreign asset used: bridged WND
 	let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000;
 	let wnd_at_rococo_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]);
 
 	// Configure destination chain to trust AH as reserve of WND
 	PenpalA::execute_with(|| {
@@ -171,7 +171,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Westend)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -293,7 +293,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() {
 	// Foreign asset used: bridged WND
 	let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000;
 	let wnd_at_rococo_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]);
 
 	// Configure destination chain to trust AH as reserve of WND
 	PenpalA::execute_with(|| {
@@ -301,7 +301,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Westend)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -455,7 +455,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Westend)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -464,14 +464,14 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
 			<PenpalB as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Westend)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
 
 	// Register WND as foreign asset and transfer it around the Rococo ecosystem
 	let wnd_at_rococo_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]);
 	AssetHubRococo::force_create_foreign_asset(
 		wnd_at_rococo_parachains.clone().try_into().unwrap(),
 		assets_owner.clone(),
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs
index 302f71f89f8..698ef2c9e79 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs
@@ -1599,7 +1599,7 @@ fn reserve_withdraw_from_untrusted_reserve_fails() {
 		]);
 		let result = <AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::execute(
 			signed_origin,
-			bx!(xcm::VersionedXcm::V4(xcm)),
+			bx!(xcm::VersionedXcm::from(xcm)),
 			Weight::MAX,
 		);
 		assert!(result.is_err());
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
index 29eaa969464..ea8f6c1defb 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs
@@ -24,7 +24,7 @@ fn send_transact_as_superuser_from_relay_to_asset_hub_works() {
 		ASSET_MIN_BALANCE,
 		true,
 		AssetHubRococoSender::get().into(),
-		Some(Weight::from_parts(1_019_445_000, 200_000)),
+		Some(Weight::from_parts(144_933_000, 3675)),
 	)
 }
 
@@ -121,7 +121,7 @@ fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() {
 		ASSET_MIN_BALANCE,
 		true,
 		para_sovereign_account.clone(),
-		Some(Weight::from_parts(1_019_445_000, 200_000)),
+		Some(Weight::from_parts(144_933_000, 3675)),
 		ASSET_MIN_BALANCE * 1000000000,
 	);
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs
index 5662a78ab67..8da1e56de21 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs
@@ -67,7 +67,7 @@ fn system_para_sets_relay_xcm_supported_version() {
 	AssetHubRococo::execute_with(|| {
 		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
 
-		AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000)));
+		AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(115_294_000, 0)));
 
 		assert_expected_events!(
 			AssetHubRococo,
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs
index 470b4d0f389..7fde929c0dc 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs
@@ -574,7 +574,7 @@ fn teleport_to_untrusted_chain_fails() {
 		]);
 		let result = <AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::execute(
 			signed_origin,
-			bx!(xcm::VersionedXcm::V4(xcm)),
+			bx!(xcm::VersionedXcm::from(xcm)),
 			Weight::MAX,
 		);
 		assert!(result.is_err());
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs
index 3320392b495..69111d38bca 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs
@@ -71,11 +71,12 @@ fn spend_roc_on_asset_hub() {
 		let teleport_call = RuntimeCall::Utility(pallet_utility::Call::<Runtime>::dispatch_as {
 			as_origin: bx!(RococoOriginCaller::system(RawOrigin::Signed(treasury_account))),
 			call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::<Runtime>::teleport_assets {
-				dest: bx!(VersionedLocation::V4(asset_hub_location.clone())),
-				beneficiary: bx!(VersionedLocation::V4(treasury_location)),
-				assets: bx!(VersionedAssets::V4(
-					Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into()
-				)),
+				dest: bx!(VersionedLocation::from(asset_hub_location.clone())),
+				beneficiary: bx!(VersionedLocation::from(treasury_location)),
+				assets: bx!(VersionedAssets::from(Assets::from(Asset {
+					id: native_asset.clone().into(),
+					fun: treasury_balance.into()
+				}))),
 				fee_asset_item: 0,
 			})),
 		});
@@ -110,12 +111,12 @@ fn spend_roc_on_asset_hub() {
 		let native_asset = Location::parent();
 
 		let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
-			asset_kind: bx!(VersionedLocatableAsset::V4 {
-				location: asset_hub_location.clone(),
-				asset_id: native_asset.into(),
-			}),
+			asset_kind: bx!(VersionedLocatableAsset::from((
+				asset_hub_location.clone(),
+				native_asset.into()
+			))),
 			amount: treasury_spend_balance,
-			beneficiary: bx!(VersionedLocation::V4(alice_location)),
+			beneficiary: bx!(VersionedLocation::from(alice_location)),
 			valid_from: None,
 		});
 
@@ -170,16 +171,12 @@ fn create_and_claim_treasury_spend_in_usdt() {
 	// treasury account on a sibling parachain.
 	let treasury_account =
 		ahr_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap();
-	let asset_hub_location =
-		v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into()));
+	let asset_hub_location = Location::new(0, Parachain(AssetHubRococo::para_id().into()));
 	let root = <Rococo as Chain>::RuntimeOrigin::root();
-	// asset kind to be spend from the treasury.
-	let asset_kind = VersionedLocatableAsset::V3 {
-		location: asset_hub_location,
-		asset_id: v3::AssetId::Concrete(
-			(v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(USDT_ID.into())).into(),
-		),
-	};
+	// asset kind to be spent from the treasury.
+	let asset_kind: VersionedLocatableAsset =
+		(asset_hub_location, AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()))
+			.into();
 	// treasury spend beneficiary.
 	let alice: AccountId = Rococo::account_id_of(ALICE);
 	let bob: AccountId = Rococo::account_id_of(BOB);
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs
index aa0e183ecdd..ea210d4f3b6 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs
@@ -16,10 +16,8 @@
 //! Tests for XCM fee estimation in the runtime.
 
 use crate::imports::*;
-use frame_support::{
-	dispatch::RawOrigin,
-	sp_runtime::{traits::Dispatchable, DispatchResult},
-};
+use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees;
+use frame_support::dispatch::RawOrigin;
 use xcm_runtime_apis::{
 	dry_run::runtime_decl_for_dry_run_api::DryRunApiV1,
 	fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1,
@@ -76,16 +74,6 @@ fn receiver_assertions(test: ParaToParaThroughAHTest) {
 	);
 }
 
-fn transfer_assets_para_to_para_through_ah_dispatchable(
-	test: ParaToParaThroughAHTest,
-) -> DispatchResult {
-	let call = transfer_assets_para_to_para_through_ah_call(test.clone());
-	match call.dispatch(test.signed_origin) {
-		Ok(_) => Ok(()),
-		Err(error_with_post_info) => Err(error_with_post_info.error),
-	}
-}
-
 fn transfer_assets_para_to_para_through_ah_call(
 	test: ParaToParaThroughAHTest,
 ) -> <PenpalA as Chain>::RuntimeCall {
@@ -100,7 +88,7 @@ fn transfer_assets_para_to_para_through_ah_call(
 		dest: bx!(test.args.dest.into()),
 		assets: bx!(test.args.assets.clone().into()),
 		assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())),
-		remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))),
+		remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::new(1, [])))),
 		fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())),
 		custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)),
 		weight_limit: test.args.weight_limit,
@@ -151,7 +139,7 @@ fn multi_hop_works() {
 
 	// We get them from the PenpalA closure.
 	let mut delivery_fees_amount = 0;
-	let mut remote_message = VersionedXcm::V4(Xcm(Vec::new()));
+	let mut remote_message = VersionedXcm::from(Xcm(Vec::new()));
 	<PenpalA as TestExt>::execute_with(|| {
 		type Runtime = <PenpalA as Chain>::Runtime;
 		type OriginCaller = <PenpalA as Chain>::OriginCaller;
@@ -164,7 +152,7 @@ fn multi_hop_works() {
 			.forwarded_xcms
 			.iter()
 			.find(|(destination, _)| {
-				*destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)]))
+				*destination == VersionedLocation::from(Location::new(1, [Parachain(1000)]))
 			})
 			.unwrap();
 		assert_eq!(messages_to_query.len(), 1);
@@ -178,7 +166,7 @@ fn multi_hop_works() {
 	// These are set in the AssetHub closure.
 	let mut intermediate_execution_fees = 0;
 	let mut intermediate_delivery_fees_amount = 0;
-	let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new()));
+	let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new()));
 	<AssetHubRococo as TestExt>::execute_with(|| {
 		type Runtime = <AssetHubRococo as Chain>::Runtime;
 		type RuntimeCall = <AssetHubRococo as Chain>::RuntimeCall;
@@ -187,13 +175,14 @@ fn multi_hop_works() {
 		let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap();
 		intermediate_execution_fees = Runtime::query_weight_to_asset_fee(
 			weight,
-			VersionedAssetId::V4(Location::new(1, []).into()),
+			VersionedAssetId::from(AssetId(Location::new(1, []))),
 		)
 		.unwrap();
 
 		// We have to do this to turn `VersionedXcm<()>` into `VersionedXcm<RuntimeCall>`.
-		let xcm_program =
-			VersionedXcm::V4(Xcm::<RuntimeCall>::from(remote_message.clone().try_into().unwrap()));
+		let xcm_program = VersionedXcm::from(Xcm::<RuntimeCall>::from(
+			remote_message.clone().try_into().unwrap(),
+		));
 
 		// Now we get the delivery fees to the final destination.
 		let result =
@@ -202,7 +191,7 @@ fn multi_hop_works() {
 			.forwarded_xcms
 			.iter()
 			.find(|(destination, _)| {
-				*destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)]))
+				*destination == VersionedLocation::from(Location::new(1, [Parachain(2001)]))
 			})
 			.unwrap();
 		// There's actually two messages here.
@@ -225,9 +214,11 @@ fn multi_hop_works() {
 		type Runtime = <PenpalA as Chain>::Runtime;
 
 		let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap();
-		final_execution_fees =
-			Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into()))
-				.unwrap();
+		final_execution_fees = Runtime::query_weight_to_asset_fee(
+			weight,
+			VersionedAssetId::from(AssetId(Location::parent())),
+		)
+		.unwrap();
 	});
 
 	// Dry-running is done.
@@ -257,7 +248,8 @@ fn multi_hop_works() {
 	test.set_assertion::<PenpalA>(sender_assertions);
 	test.set_assertion::<AssetHubRococo>(hop_assertions);
 	test.set_assertion::<PenpalB>(receiver_assertions);
-	test.set_dispatchable::<PenpalA>(transfer_assets_para_to_para_through_ah_dispatchable);
+	let call = transfer_assets_para_to_para_through_ah_call(test.clone());
+	test.set_call(call);
 	test.assert();
 
 	let sender_assets_after = PenpalA::execute_with(|| {
@@ -284,3 +276,14 @@ fn multi_hop_works() {
 			final_execution_fees
 	);
 }
+
+#[test]
+fn multi_hop_pay_fees_works() {
+	test_can_estimate_and_pay_exact_fees!(
+		PenpalA,
+		AssetHubRococo,
+		PenpalB,
+		(Parent, 1_000_000_000_000u128),
+		Penpal
+	);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
index 872a8ffa6a8..71e44e5cee7 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
@@ -31,6 +31,7 @@ pallet-asset-tx-payment = { workspace = true }
 # Polkadot
 polkadot-runtime-common = { workspace = true, default-features = true }
 xcm = { workspace = true }
+xcm-builder = { workspace = true }
 xcm-executor = { workspace = true }
 pallet-xcm = { workspace = true }
 xcm-runtime-apis = { workspace = true }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs
index 179a44e14aa..3cca99fbfe5 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs
@@ -26,7 +26,10 @@ mod imports {
 	};
 
 	// Polkadot
-	pub use xcm::prelude::{AccountId32 as AccountId32Junction, *};
+	pub use xcm::{
+		latest::{AssetTransferFilter, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH},
+		prelude::{AccountId32 as AccountId32Junction, *},
+	};
 	pub use xcm_executor::traits::TransferType;
 
 	// Cumulus
@@ -42,7 +45,7 @@ mod imports {
 		xcm_helpers::{
 			get_amount_from_versioned_assets, non_fee_asset, xcm_transact_paid_execution,
 		},
-		ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3,
+		ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, USDT_ID, XCM_V3,
 	};
 	pub use parachains_common::{AccountId, Balance};
 	pub use westend_system_emulated_network::{
@@ -59,12 +62,16 @@ mod imports {
 			genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED},
 			AssetHubWestendParaPallet as AssetHubWestendPallet,
 		},
+		bridge_hub_westend_emulated_chain::bridge_hub_westend_runtime::xcm_config::{
+			self as bhw_xcm_config,
+		},
 		collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet,
 		penpal_emulated_chain::{
 			penpal_runtime::xcm_config::{
 				CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub,
 				LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub,
 				LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub,
+				UniversalLocation as PenpalUniversalLocation,
 				UsdtFromAssetHub as PenpalUsdtFromAssetHub,
 			},
 			PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner,
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
index de58839634f..90af907654f 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = AssetHubWestendExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount);
+	test_chain_can_claim_assets!(
+		AssetHubWestend,
+		RuntimeCall,
+		NetworkId::ByGenesis(WESTEND_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs
index 9520659712f..124ec2ec1f6 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs
@@ -34,10 +34,9 @@ fn create_and_claim_treasury_spend() {
 	let asset_hub_location = Location::new(1, [Parachain(AssetHubWestend::para_id().into())]);
 	let root = <CollectivesWestend as Chain>::RuntimeOrigin::root();
 	// asset kind to be spent from the treasury.
-	let asset_kind = VersionedLocatableAsset::V4 {
-		location: asset_hub_location,
-		asset_id: AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()),
-	};
+	let asset_kind: VersionedLocatableAsset =
+		(asset_hub_location, AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()))
+			.into();
 	// treasury spend beneficiary.
 	let alice: AccountId = Westend::account_id_of(ALICE);
 	let bob: AccountId = CollectivesWestend::account_id_of(BOB);
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs
index 4d6cdd9a94d..a0fc82fba6e 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs
@@ -163,7 +163,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() {
 	// Foreign asset used: bridged ROC
 	let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000;
 	let roc_at_westend_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]);
 
 	// Configure destination chain to trust AH as reserve of ROC
 	PenpalA::execute_with(|| {
@@ -171,7 +171,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Rococo)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -293,7 +293,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() {
 	// Foreign asset used: bridged ROC
 	let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000;
 	let roc_at_westend_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]);
 
 	// Configure destination chain to trust AH as reserve of ROC
 	PenpalA::execute_with(|| {
@@ -301,7 +301,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Rococo)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -456,7 +456,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
 			<PenpalA as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Rococo)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
@@ -465,14 +465,14 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() {
 			<PenpalB as Chain>::RuntimeOrigin::root(),
 			vec![(
 				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
-				Location::new(2, [GlobalConsensus(Rococo)]).encode(),
+				Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(),
 			)],
 		));
 	});
 
 	// Register ROC as foreign asset and transfer it around the Westend ecosystem
 	let roc_at_westend_parachains =
-		Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]);
+		Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]);
 	AssetHubWestend::force_create_foreign_asset(
 		roc_at_westend_parachains.clone().try_into().unwrap(),
 		assets_owner.clone(),
@@ -819,3 +819,88 @@ fn transfer_native_asset_from_relay_to_para_through_asset_hub() {
 	// should be non-zero
 	assert!(receiver_assets_after < receiver_assets_before + amount_to_send);
 }
+
+// ==============================================================================================
+// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ====
+// ==============================================================================================
+/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back
+/// with fees paid using native asset.
+#[test]
+fn bidirectional_transfer_multiple_assets_between_penpal_and_asset_hub() {
+	fn execute_xcm_penpal_to_asset_hub(t: ParaToSystemParaTest) -> DispatchResult {
+		let all_assets = t.args.assets.clone().into_inner();
+		let mut assets = all_assets.clone();
+		let mut fees = assets.remove(t.args.fee_asset_item as usize);
+		// TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get exact fees.
+		// For now just use half the fees locally, half on dest
+		if let Fungible(fees_amount) = fees.fun {
+			fees.fun = Fungible(fees_amount / 2);
+		}
+		// xcm to be executed at dest
+		let xcm_on_dest = Xcm(vec![
+			// since this is the last hop, we don't need to further use any assets previously
+			// reserved for fees (there are no further hops to cover transport fees for); we
+			// RefundSurplus to get back any unspent fees
+			RefundSurplus,
+			DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary },
+		]);
+		let xcm = Xcm::<()>(vec![
+			WithdrawAsset(all_assets.into()),
+			PayFees { asset: fees.clone() },
+			InitiateTransfer {
+				destination: t.args.dest,
+				remote_fees: Some(AssetTransferFilter::ReserveWithdraw(fees.into())),
+				preserve_origin: false,
+				assets: vec![AssetTransferFilter::Teleport(assets.into())],
+				remote_xcm: xcm_on_dest,
+			},
+		]);
+		<PenpalA as PenpalAPallet>::PolkadotXcm::execute(
+			t.signed_origin,
+			bx!(xcm::VersionedXcm::from(xcm.into())),
+			Weight::MAX,
+		)
+		.unwrap();
+		Ok(())
+	}
+	fn execute_xcm_asset_hub_to_penpal(t: SystemParaToParaTest) -> DispatchResult {
+		let all_assets = t.args.assets.clone().into_inner();
+		let mut assets = all_assets.clone();
+		let mut fees = assets.remove(t.args.fee_asset_item as usize);
+		// TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get exact fees.
+		// For now just use half the fees locally, half on dest
+		if let Fungible(fees_amount) = fees.fun {
+			fees.fun = Fungible(fees_amount / 2);
+		}
+		// xcm to be executed at dest
+		let xcm_on_dest = Xcm(vec![
+			// since this is the last hop, we don't need to further use any assets previously
+			// reserved for fees (there are no further hops to cover transport fees for); we
+			// RefundSurplus to get back any unspent fees
+			RefundSurplus,
+			DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary },
+		]);
+		let xcm = Xcm::<()>(vec![
+			WithdrawAsset(all_assets.into()),
+			PayFees { asset: fees.clone() },
+			InitiateTransfer {
+				destination: t.args.dest,
+				remote_fees: Some(AssetTransferFilter::ReserveDeposit(fees.into())),
+				preserve_origin: false,
+				assets: vec![AssetTransferFilter::Teleport(assets.into())],
+				remote_xcm: xcm_on_dest,
+			},
+		]);
+		<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::execute(
+			t.signed_origin,
+			bx!(xcm::VersionedXcm::from(xcm.into())),
+			Weight::MAX,
+		)
+		.unwrap();
+		Ok(())
+	}
+	do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt(
+		execute_xcm_penpal_to_asset_hub,
+		execute_xcm_asset_hub_to_penpal,
+	);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs
index 73b73b239a1..0dfe7a85f4c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs
@@ -18,8 +18,86 @@ mod fellowship_treasury;
 mod hybrid_transfers;
 mod reserve_transfer;
 mod send;
+mod set_asset_claimer;
 mod set_xcm_versions;
 mod swap;
 mod teleport;
+mod transact;
 mod treasury;
 mod xcm_fee_estimation;
+
+#[macro_export]
+macro_rules! foreign_balance_on {
+	( $chain:ident, $id:expr, $who:expr ) => {
+		emulated_integration_tests_common::impls::paste::paste! {
+			<$chain>::execute_with(|| {
+				type ForeignAssets = <$chain as [<$chain Pallet>]>::ForeignAssets;
+				<ForeignAssets as Inspect<_>>::balance($id, $who)
+			})
+		}
+	};
+}
+
+#[macro_export]
+macro_rules! create_pool_with_wnd_on {
+	( $chain:ident, $asset_id:expr, $is_foreign:expr, $asset_owner:expr ) => {
+		emulated_integration_tests_common::impls::paste::paste! {
+			<$chain>::execute_with(|| {
+				type RuntimeEvent = <$chain as Chain>::RuntimeEvent;
+				let owner = $asset_owner;
+				let signed_owner = <$chain as Chain>::RuntimeOrigin::signed(owner.clone());
+				let wnd_location: Location = Parent.into();
+				if $is_foreign {
+					assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint(
+						signed_owner.clone(),
+						$asset_id.clone().into(),
+						owner.clone().into(),
+						10_000_000_000_000, // For it to have more than enough.
+					));
+				} else {
+					let asset_id = match $asset_id.interior.last() {
+						Some(GeneralIndex(id)) => *id as u32,
+						_ => unreachable!(),
+					};
+					assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint(
+						signed_owner.clone(),
+						asset_id.into(),
+						owner.clone().into(),
+						10_000_000_000_000, // For it to have more than enough.
+					));
+				}
+
+				assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool(
+					signed_owner.clone(),
+					Box::new(wnd_location.clone()),
+					Box::new($asset_id.clone()),
+				));
+
+				assert_expected_events!(
+					$chain,
+					vec![
+						RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
+					]
+				);
+
+				assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity(
+					signed_owner,
+					Box::new(wnd_location),
+					Box::new($asset_id),
+					1_000_000_000_000,
+					2_000_000_000_000, // $asset_id is worth half of wnd
+					0,
+					0,
+					owner.into()
+				));
+
+				assert_expected_events!(
+					$chain,
+					vec![
+						RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
+					]
+				);
+			});
+		}
+	};
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs
index 10c27c338ec..558eab13e5c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs
@@ -13,7 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::imports::*;
+use crate::{create_pool_with_wnd_on, foreign_balance_on, imports::*};
 use sp_core::{crypto::get_public_from_string_or_panic, sr25519};
 
 fn relay_to_para_sender_assertions(t: RelayToParaTest) {
@@ -651,10 +651,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() {
 
 	// Query initial balances
 	let sender_balance_before = test.sender.balance;
-	let receiver_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &receiver)
-	});
+	let receiver_assets_before =
+		foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &receiver);
 
 	// Set assertions and dispatchables
 	test.set_assertion::<Westend>(relay_to_para_sender_assertions);
@@ -664,10 +662,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() {
 
 	// Query final balances
 	let sender_balance_after = test.sender.balance;
-	let receiver_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location, &receiver)
-	});
+	let receiver_assets_after =
+		foreign_balance_on!(PenpalA, relay_native_asset_location, &receiver);
 
 	// Sender's balance is reduced by amount sent plus delivery fees
 	assert!(sender_balance_after < sender_balance_before - amount_to_send);
@@ -722,10 +718,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() {
 	let mut test = ParaToRelayTest::new(test_args);
 
 	// Query initial balances
-	let sender_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &sender)
-	});
+	let sender_assets_before =
+		foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender);
 	let receiver_balance_before = test.receiver.balance;
 
 	// Set assertions and dispatchables
@@ -735,10 +729,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() {
 	test.assert();
 
 	// Query final balances
-	let sender_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location, &sender)
-	});
+	let sender_assets_after = foreign_balance_on!(PenpalA, relay_native_asset_location, &sender);
 	let receiver_balance_after = test.receiver.balance;
 
 	// Sender's balance is reduced by amount sent plus delivery fees
@@ -784,10 +775,8 @@ fn reserve_transfer_native_asset_from_asset_hub_to_para() {
 
 	// Query initial balances
 	let sender_balance_before = test.sender.balance;
-	let receiver_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location.clone(), &receiver)
-	});
+	let receiver_assets_before =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &receiver);
 
 	// Set assertions and dispatchables
 	test.set_assertion::<AssetHubWestend>(system_para_to_para_sender_assertions);
@@ -797,10 +786,8 @@ fn reserve_transfer_native_asset_from_asset_hub_to_para() {
 
 	// Query final balances
 	let sender_balance_after = test.sender.balance;
-	let receiver_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location, &receiver)
-	});
+	let receiver_assets_after =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location, &receiver);
 
 	// Sender's balance is reduced by amount sent plus delivery fees
 	assert!(sender_balance_after < sender_balance_before - amount_to_send);
@@ -856,10 +843,8 @@ fn reserve_transfer_native_asset_from_para_to_asset_hub() {
 	let mut test = ParaToSystemParaTest::new(test_args);
 
 	// Query initial balances
-	let sender_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location.clone(), &sender)
-	});
+	let sender_assets_before =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &sender);
 	let receiver_balance_before = test.receiver.balance;
 
 	// Set assertions and dispatchables
@@ -869,10 +854,8 @@ fn reserve_transfer_native_asset_from_para_to_asset_hub() {
 	test.assert();
 
 	// Query final balances
-	let sender_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location, &sender)
-	});
+	let sender_assets_after =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location, &sender);
 	let receiver_balance_after = test.receiver.balance;
 
 	// Sender's balance is reduced by amount sent plus delivery fees
@@ -950,17 +933,10 @@ fn reserve_transfer_multiple_assets_from_asset_hub_to_para() {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
 		<Assets as Inspect<_>>::balance(RESERVABLE_ASSET_ID, &sender)
 	});
-	let receiver_system_native_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location.clone(), &receiver)
-	});
-	let receiver_foreign_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			system_para_foreign_asset_location.clone(),
-			&receiver,
-		)
-	});
+	let receiver_system_native_assets_before =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &receiver);
+	let receiver_foreign_assets_before =
+		foreign_balance_on!(PenpalA, system_para_foreign_asset_location.clone(), &receiver);
 
 	// Set assertions and dispatchables
 	test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_sender_assertions);
@@ -974,14 +950,10 @@ fn reserve_transfer_multiple_assets_from_asset_hub_to_para() {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
 		<Assets as Inspect<_>>::balance(RESERVABLE_ASSET_ID, &sender)
 	});
-	let receiver_system_native_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_native_asset_location, &receiver)
-	});
-	let receiver_foreign_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_para_foreign_asset_location, &receiver)
-	});
+	let receiver_system_native_assets_after =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location, &receiver);
+	let receiver_foreign_assets_after =
+		foreign_balance_on!(PenpalA, system_para_foreign_asset_location.clone(), &receiver);
 	// Sender's balance is reduced
 	assert!(sender_balance_after < sender_balance_before);
 	// Receiver's foreign asset balance is increased
@@ -1082,14 +1054,10 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() {
 	let mut test = ParaToSystemParaTest::new(para_test_args);
 
 	// Query initial balances
-	let sender_system_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_asset_location_on_penpal.clone(), &sender)
-	});
-	let sender_foreign_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(asset_location_on_penpal.clone(), &sender)
-	});
+	let sender_system_assets_before =
+		foreign_balance_on!(PenpalA, system_asset_location_on_penpal.clone(), &sender);
+	let sender_foreign_assets_before =
+		foreign_balance_on!(PenpalA, asset_location_on_penpal.clone(), &sender);
 	let receiver_balance_before = test.receiver.balance;
 	let receiver_assets_before = AssetHubWestend::execute_with(|| {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
@@ -1103,14 +1071,10 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() {
 	test.assert();
 
 	// Query final balances
-	let sender_system_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(system_asset_location_on_penpal, &sender)
-	});
-	let sender_foreign_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(asset_location_on_penpal, &sender)
-	});
+	let sender_system_assets_after =
+		foreign_balance_on!(PenpalA, system_asset_location_on_penpal, &sender);
+	let sender_foreign_assets_after =
+		foreign_balance_on!(PenpalA, asset_location_on_penpal, &sender);
 	let receiver_balance_after = test.receiver.balance;
 	let receiver_assets_after = AssetHubWestend::execute_with(|| {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
@@ -1171,14 +1135,10 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() {
 	let mut test = ParaToParaThroughRelayTest::new(test_args);
 
 	// Query initial balances
-	let sender_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &sender)
-	});
-	let receiver_assets_before = PenpalB::execute_with(|| {
-		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &receiver)
-	});
+	let sender_assets_before =
+		foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender);
+	let receiver_assets_before =
+		foreign_balance_on!(PenpalB, relay_native_asset_location.clone(), &receiver);
 
 	// Set assertions and dispatchables
 	test.set_assertion::<PenpalA>(para_to_para_through_hop_sender_assertions);
@@ -1188,14 +1148,10 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() {
 	test.assert();
 
 	// Query final balances
-	let sender_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location.clone(), &sender)
-	});
-	let receiver_assets_after = PenpalB::execute_with(|| {
-		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(relay_native_asset_location, &receiver)
-	});
+	let sender_assets_after =
+		foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender);
+	let receiver_assets_after =
+		foreign_balance_on!(PenpalB, relay_native_asset_location, &receiver);
 
 	// Sender's balance is reduced by amount sent plus delivery fees.
 	assert!(sender_assets_after < sender_assets_before - amount_to_send);
@@ -1231,55 +1187,11 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() {
 		));
 	});
 
-	let relay_asset_penpal_pov = RelayLocation::get();
-
 	let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get();
-
 	// Setup the pool between `relay_asset_penpal_pov` and `usdt_from_asset_hub` on PenpalA.
 	// So we can swap the custom asset that comes from AssetHubWestend for native asset to pay for
 	// fees.
-	PenpalA::execute_with(|| {
-		type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
-
-		assert_ok!(<PenpalA as PenpalAPallet>::ForeignAssets::mint(
-			<PenpalA as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()),
-			usdt_from_asset_hub.clone().into(),
-			PenpalASender::get().into(),
-			10_000_000_000_000, // For it to have more than enough.
-		));
-
-		assert_ok!(<PenpalA as PenpalAPallet>::AssetConversion::create_pool(
-			<PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get()),
-			Box::new(relay_asset_penpal_pov.clone()),
-			Box::new(usdt_from_asset_hub.clone()),
-		));
-
-		assert_expected_events!(
-			PenpalA,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
-			]
-		);
-
-		assert_ok!(<PenpalA as PenpalAPallet>::AssetConversion::add_liquidity(
-			<PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get()),
-			Box::new(relay_asset_penpal_pov),
-			Box::new(usdt_from_asset_hub.clone()),
-			// `usdt_from_asset_hub` is worth a third of `relay_asset_penpal_pov`
-			1_000_000_000_000,
-			3_000_000_000_000,
-			0,
-			0,
-			PenpalASender::get().into()
-		));
-
-		assert_expected_events!(
-			PenpalA,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
-			]
-		);
-	});
+	create_pool_with_wnd_on!(PenpalA, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get());
 
 	let assets: Assets = vec![(
 		[PalletInstance(ASSETS_PALLET_ID), GeneralIndex(usdt_id.into())],
@@ -1310,10 +1222,8 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() {
 		type Balances = <AssetHubWestend as AssetHubWestendPallet>::Balances;
 		Balances::free_balance(&sender)
 	});
-	let receiver_initial_balance = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub.clone(), &receiver)
-	});
+	let receiver_initial_balance =
+		foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &receiver);
 
 	test.set_assertion::<AssetHubWestend>(system_para_to_para_sender_assertions);
 	test.set_assertion::<PenpalA>(system_para_to_para_receiver_assertions);
@@ -1328,10 +1238,7 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() {
 		type Balances = <AssetHubWestend as AssetHubWestendPallet>::Balances;
 		Balances::free_balance(&sender)
 	});
-	let receiver_after_balance = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub, &receiver)
-	});
+	let receiver_after_balance = foreign_balance_on!(PenpalA, usdt_from_asset_hub, &receiver);
 
 	// TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we allow payment with different assets locally, this should be the same, since
 	// they aren't used for fees.
@@ -1371,7 +1278,7 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() {
 	]);
 
 	// Give USDT to sov account of sender.
-	let usdt_id = 1984;
+	let usdt_id: u32 = 1984;
 	AssetHubWestend::execute_with(|| {
 		use frame_support::traits::tokens::fungibles::Mutate;
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
@@ -1383,101 +1290,15 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() {
 	});
 
 	// We create a pool between WND and USDT in AssetHub.
-	let native_asset: Location = Parent.into();
 	let usdt = Location::new(
 		0,
 		[Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(usdt_id.into())],
 	);
-
-	// set up pool with USDT <> native pair
-	AssetHubWestend::execute_with(|| {
-		type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
-
-		assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::Assets::mint(
-			<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
-			usdt_id.into(),
-			AssetHubWestendSender::get().into(),
-			10_000_000_000_000, // For it to have more than enough.
-		));
-
-		assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool(
-			<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
-			Box::new(native_asset.clone()),
-			Box::new(usdt.clone()),
-		));
-
-		assert_expected_events!(
-			AssetHubWestend,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
-			]
-		);
-
-		assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity(
-			<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
-			Box::new(native_asset),
-			Box::new(usdt),
-			1_000_000_000_000,
-			2_000_000_000_000, // usdt is worth half of `native_asset`
-			0,
-			0,
-			AssetHubWestendSender::get().into()
-		));
-
-		assert_expected_events!(
-			AssetHubWestend,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
-			]
-		);
-	});
-
-	let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get();
-
+	create_pool_with_wnd_on!(AssetHubWestend, usdt, false, AssetHubWestendSender::get());
 	// We also need a pool between WND and USDT on PenpalB.
-	PenpalB::execute_with(|| {
-		type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
-		let relay_asset = RelayLocation::get();
-
-		assert_ok!(<PenpalB as PenpalBPallet>::ForeignAssets::mint(
-			<PenpalB as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()),
-			usdt_from_asset_hub.clone().into(),
-			PenpalBReceiver::get().into(),
-			10_000_000_000_000, // For it to have more than enough.
-		));
-
-		assert_ok!(<PenpalB as PenpalBPallet>::AssetConversion::create_pool(
-			<PenpalB as Chain>::RuntimeOrigin::signed(PenpalBReceiver::get()),
-			Box::new(relay_asset.clone()),
-			Box::new(usdt_from_asset_hub.clone()),
-		));
-
-		assert_expected_events!(
-			PenpalB,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
-			]
-		);
-
-		assert_ok!(<PenpalB as PenpalBPallet>::AssetConversion::add_liquidity(
-			<PenpalB as Chain>::RuntimeOrigin::signed(PenpalBReceiver::get()),
-			Box::new(relay_asset),
-			Box::new(usdt_from_asset_hub.clone()),
-			1_000_000_000_000,
-			2_000_000_000_000, // `usdt_from_asset_hub` is worth half of `relay_asset`
-			0,
-			0,
-			PenpalBReceiver::get().into()
-		));
-
-		assert_expected_events!(
-			PenpalB,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
-			]
-		);
-	});
+	create_pool_with_wnd_on!(PenpalB, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get());
 
+	let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get();
 	PenpalA::execute_with(|| {
 		use frame_support::traits::tokens::fungibles::Mutate;
 		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
@@ -1523,14 +1344,9 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() {
 	let mut test = ParaToParaThroughAHTest::new(test_args);
 
 	// Query initial balances
-	let sender_assets_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub.clone(), &sender)
-	});
-	let receiver_assets_before = PenpalB::execute_with(|| {
-		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub.clone(), &receiver)
-	});
+	let sender_assets_before = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender);
+	let receiver_assets_before =
+		foreign_balance_on!(PenpalB, usdt_from_asset_hub.clone(), &receiver);
 	test.set_assertion::<PenpalA>(para_to_para_through_hop_sender_assertions);
 	test.set_assertion::<AssetHubWestend>(para_to_para_asset_hub_hop_assertions);
 	test.set_assertion::<PenpalB>(para_to_para_through_hop_receiver_assertions);
@@ -1540,14 +1356,8 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() {
 	test.assert();
 
 	// Query final balances
-	let sender_assets_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub.clone(), &sender)
-	});
-	let receiver_assets_after = PenpalB::execute_with(|| {
-		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(usdt_from_asset_hub, &receiver)
-	});
+	let sender_assets_after = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender);
+	let receiver_assets_after = foreign_balance_on!(PenpalB, usdt_from_asset_hub, &receiver);
 
 	// Sender's balance is reduced by amount
 	assert!(sender_assets_after < sender_assets_before - asset_amount_to_send);
@@ -1603,7 +1413,7 @@ fn reserve_withdraw_from_untrusted_reserve_fails() {
 		]);
 		let result = <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::execute(
 			signed_origin,
-			bx!(xcm::VersionedXcm::V4(xcm)),
+			bx!(xcm::VersionedXcm::from(xcm)),
 			Weight::MAX,
 		);
 		assert!(result.is_err());
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
index 761c7c12255..d4f239df487 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs
@@ -24,7 +24,7 @@ fn send_transact_as_superuser_from_relay_to_asset_hub_works() {
 		ASSET_MIN_BALANCE,
 		true,
 		AssetHubWestendSender::get().into(),
-		Some(Weight::from_parts(1_019_445_000, 200_000)),
+		Some(Weight::from_parts(144_759_000, 3675)),
 	)
 }
 
@@ -121,7 +121,7 @@ fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() {
 		ASSET_MIN_BALANCE,
 		true,
 		para_sovereign_account.clone(),
-		Some(Weight::from_parts(1_019_445_000, 200_000)),
+		Some(Weight::from_parts(144_759_000, 3675)),
 		ASSET_MIN_BALANCE * 1000000000,
 	);
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs
new file mode 100644
index 00000000000..544b0536052
--- /dev/null
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs
@@ -0,0 +1,154 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests related to claiming assets trapped during XCM execution.
+
+use crate::imports::{bhw_xcm_config::LocationToAccountId, *};
+use emulated_integration_tests_common::{
+	accounts::{ALICE, BOB},
+	impls::AccountId32,
+};
+use frame_support::{assert_ok, sp_runtime::traits::Dispatchable};
+use westend_system_emulated_network::{
+	asset_hub_westend_emulated_chain::asset_hub_westend_runtime::RuntimeOrigin as AssetHubRuntimeOrigin,
+	bridge_hub_westend_emulated_chain::bridge_hub_westend_runtime::RuntimeOrigin as BridgeHubRuntimeOrigin,
+};
+use xcm_executor::traits::ConvertLocation;
+
+#[test]
+fn test_set_asset_claimer_within_a_chain() {
+	let (alice_account, _) = account_and_location(ALICE);
+	let (bob_account, bob_location) = account_and_location(BOB);
+
+	let trap_amount = 16_000_000_000_000;
+	let assets: Assets = (Parent, trap_amount).into();
+
+	let alice_balance_before =
+		<AssetHubWestend as Chain>::account_data_of(alice_account.clone()).free;
+	AssetHubWestend::fund_accounts(vec![(alice_account.clone(), trap_amount * 2)]);
+	let alice_balance_after =
+		<AssetHubWestend as Chain>::account_data_of(alice_account.clone()).free;
+	assert_eq!(alice_balance_after - alice_balance_before, trap_amount * 2);
+
+	type RuntimeCall = <AssetHubWestend as Chain>::RuntimeCall;
+	let asset_trap_xcm = Xcm::<RuntimeCall>::builder_unsafe()
+		.set_asset_claimer(bob_location.clone())
+		.withdraw_asset(assets.clone())
+		.clear_origin()
+		.build();
+
+	AssetHubWestend::execute_with(|| {
+		assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute {
+			message: bx!(VersionedXcm::from(asset_trap_xcm)),
+			max_weight: Weight::from_parts(4_000_000_000_000, 300_000),
+		})
+		.dispatch(AssetHubRuntimeOrigin::signed(alice_account.clone())));
+	});
+
+	let balance_after_trap =
+		<AssetHubWestend as Chain>::account_data_of(alice_account.clone()).free;
+	assert_eq!(alice_balance_after - balance_after_trap, trap_amount);
+
+	let bob_balance_before = <AssetHubWestend as Chain>::account_data_of(bob_account.clone()).free;
+	let claim_xcm = Xcm::<RuntimeCall>::builder_unsafe()
+		.claim_asset(assets.clone(), Here)
+		.deposit_asset(AllCounted(assets.len() as u32), bob_location.clone())
+		.build();
+
+	AssetHubWestend::execute_with(|| {
+		assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute {
+			message: bx!(VersionedXcm::from(claim_xcm)),
+			max_weight: Weight::from_parts(4_000_000_000_000, 300_000),
+		})
+		.dispatch(AssetHubRuntimeOrigin::signed(bob_account.clone())));
+	});
+
+	let bob_balance_after = <AssetHubWestend as Chain>::account_data_of(bob_account.clone()).free;
+	assert_eq!(bob_balance_after - bob_balance_before, trap_amount);
+}
+
+fn account_and_location(account: &str) -> (AccountId32, Location) {
+	let account_id = AssetHubWestend::account_id_of(account);
+	let account_clone = account_id.clone();
+	let location: Location = [Junction::AccountId32 {
+		network: Some(ByGenesis(WESTEND_GENESIS_HASH)),
+		id: account_id.into(),
+	}]
+	.into();
+	(account_clone, location)
+}
+
+// The test:
+// 1. Funds Bob account on BridgeHub, withdraws the funds, sets asset claimer to
+// sibling-account-of(AssetHub/Alice) and traps the funds.
+// 2. Alice on AssetHub sends an XCM to BridgeHub to claim assets, pay fees and deposit
+// remaining to her sibling account on BridgeHub.
+#[test]
+fn test_set_asset_claimer_between_the_chains() {
+	let alice = AssetHubWestend::account_id_of(ALICE);
+	let alice_bh_sibling = Location::new(
+		1,
+		[
+			Parachain(AssetHubWestend::para_id().into()),
+			Junction::AccountId32 {
+				network: Some(ByGenesis(WESTEND_GENESIS_HASH)),
+				id: alice.clone().into(),
+			},
+		],
+	);
+
+	let bob = BridgeHubWestend::account_id_of(BOB);
+	let trap_amount = 16_000_000_000_000u128;
+	BridgeHubWestend::fund_accounts(vec![(bob.clone(), trap_amount * 2)]);
+
+	let assets: Assets = (Parent, trap_amount).into();
+	type RuntimeCall = <BridgeHubWestend as Chain>::RuntimeCall;
+	let trap_xcm = Xcm::<RuntimeCall>::builder_unsafe()
+		.set_asset_claimer(alice_bh_sibling.clone())
+		.withdraw_asset(assets.clone())
+		.clear_origin()
+		.build();
+
+	BridgeHubWestend::execute_with(|| {
+		assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute {
+			message: bx!(VersionedXcm::from(trap_xcm)),
+			max_weight: Weight::from_parts(4_000_000_000_000, 700_000),
+		})
+		.dispatch(BridgeHubRuntimeOrigin::signed(bob.clone())));
+	});
+
+	let alice_bh_acc = LocationToAccountId::convert_location(&alice_bh_sibling).unwrap();
+	let balance = <BridgeHubWestend as Chain>::account_data_of(alice_bh_acc.clone()).free;
+	assert_eq!(balance, 0);
+
+	let pay_fees = 6_000_000_000_000u128;
+	let xcm_on_bh = Xcm::<()>::builder_unsafe()
+		.claim_asset(assets.clone(), Here)
+		.pay_fees((Parent, pay_fees))
+		.deposit_asset(All, alice_bh_sibling.clone())
+		.build();
+	let bh_on_ah = AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()).into();
+	AssetHubWestend::execute_with(|| {
+		assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::send(
+			AssetHubRuntimeOrigin::signed(alice.clone()),
+			bx!(bh_on_ah),
+			bx!(VersionedXcm::from(xcm_on_bh)),
+		));
+	});
+
+	let alice_bh_acc = LocationToAccountId::convert_location(&alice_bh_sibling).unwrap();
+	let balance = <BridgeHubWestend as Chain>::account_data_of(alice_bh_acc).free;
+	assert_eq!(balance, trap_amount - pay_fees);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs
index 474e9a86ccc..4405ed2988a 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs
@@ -67,10 +67,7 @@ fn system_para_sets_relay_xcm_supported_version() {
 	AssetHubWestend::execute_with(|| {
 		type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
 
-		AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(
-			1_019_210_000,
-			200_000,
-		)));
+		AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(115_688_000, 0)));
 
 		assert_expected_events!(
 			AssetHubWestend,
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs
index ee0f297792f..0897c187e7c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs
@@ -13,7 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::imports::*;
+use crate::{foreign_balance_on, imports::*};
 
 fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) {
 	Westend::assert_ump_queue_processed(
@@ -112,16 +112,6 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) {
 	assert_expected_events!(
 		AssetHubWestend,
 		vec![
-			// native asset used for fees is transferred to Parachain's Sovereign account as reserve
-			RuntimeEvent::Balances(
-				pallet_balances::Event::Transfer { from, to, amount }
-			) => {
-				from: *from == t.sender.account_id,
-				to: *to == AssetHubWestend::sovereign_account_id_of(
-					t.args.dest.clone()
-				),
-				amount: *amount == t.args.amount,
-			},
 			// foreign asset is burned locally as part of teleportation
 			RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
 				asset_id: *asset_id == expected_foreign_asset_id,
@@ -283,13 +273,13 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 	ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult,
 ) {
 	// Init values for Parachain
-	let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 100;
+	let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000;
 	let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get();
 	let asset_id_on_penpal = match asset_location_on_penpal.last() {
 		Some(Junction::GeneralIndex(id)) => *id as u32,
 		_ => unreachable!(),
 	};
-	let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100;
+	let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 1000;
 	let asset_owner = PenpalAssetOwner::get();
 	let system_para_native_asset_location = RelayLocation::get();
 	let sender = PenpalASender::get();
@@ -318,7 +308,7 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 		<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
 		asset_id_on_penpal,
 		sender.clone(),
-		asset_amount_to_send,
+		asset_amount_to_send * 2,
 	);
 	// fund Parachain's check account to be able to teleport
 	PenpalA::fund_accounts(vec![(
@@ -335,7 +325,7 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 	)]);
 
 	// Init values for System Parachain
-	let foreign_asset_at_asset_hub_westend =
+	let foreign_asset_at_asset_hub =
 		Location::new(1, [Junction::Parachain(PenpalA::para_id().into())])
 			.appended_with(asset_location_on_penpal)
 			.unwrap();
@@ -355,13 +345,11 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 		),
 	};
 	let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args);
-	let penpal_sender_balance_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			system_para_native_asset_location.clone(),
-			&PenpalASender::get(),
-		)
-	});
+	let penpal_sender_balance_before = foreign_balance_on!(
+		PenpalA,
+		system_para_native_asset_location.clone(),
+		&PenpalASender::get()
+	);
 
 	let ah_receiver_balance_before = penpal_to_ah.receiver.balance;
 
@@ -369,26 +357,22 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 		type Assets = <PenpalA as PenpalAPallet>::Assets;
 		<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
 	});
-	let ah_receiver_assets_before = AssetHubWestend::execute_with(|| {
-		type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
-		<Assets as Inspect<_>>::balance(
-			foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(),
-			&AssetHubWestendReceiver::get(),
-		)
-	});
+	let ah_receiver_assets_before = foreign_balance_on!(
+		AssetHubWestend,
+		foreign_asset_at_asset_hub.clone(),
+		&AssetHubWestendReceiver::get()
+	);
 
 	penpal_to_ah.set_assertion::<PenpalA>(penpal_to_ah_foreign_assets_sender_assertions);
 	penpal_to_ah.set_assertion::<AssetHubWestend>(penpal_to_ah_foreign_assets_receiver_assertions);
 	penpal_to_ah.set_dispatchable::<PenpalA>(para_to_ah_dispatchable);
 	penpal_to_ah.assert();
 
-	let penpal_sender_balance_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			system_para_native_asset_location.clone(),
-			&PenpalASender::get(),
-		)
-	});
+	let penpal_sender_balance_after = foreign_balance_on!(
+		PenpalA,
+		system_para_native_asset_location.clone(),
+		&PenpalASender::get()
+	);
 
 	let ah_receiver_balance_after = penpal_to_ah.receiver.balance;
 
@@ -396,13 +380,11 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 		type Assets = <PenpalA as PenpalAPallet>::Assets;
 		<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
 	});
-	let ah_receiver_assets_after = AssetHubWestend::execute_with(|| {
-		type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
-		<Assets as Inspect<_>>::balance(
-			foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(),
-			&AssetHubWestendReceiver::get(),
-		)
-	});
+	let ah_receiver_assets_after = foreign_balance_on!(
+		AssetHubWestend,
+		foreign_asset_at_asset_hub.clone(),
+		&AssetHubWestendReceiver::get()
+	);
 
 	// Sender's balance is reduced
 	assert!(penpal_sender_balance_after < penpal_sender_balance_before);
@@ -427,17 +409,21 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 		type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
 		assert_ok!(ForeignAssets::transfer(
 			<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendReceiver::get()),
-			foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(),
+			foreign_asset_at_asset_hub.clone().try_into().unwrap(),
 			AssetHubWestendSender::get().into(),
 			asset_amount_to_send,
 		));
 	});
 
+	// Only send back half the amount.
+	let asset_amount_to_send = asset_amount_to_send / 2;
+	let fee_amount_to_send = fee_amount_to_send / 2;
+
 	let ah_to_penpal_beneficiary_id = PenpalAReceiver::get();
 	let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id());
 	let ah_assets: Assets = vec![
 		(Parent, fee_amount_to_send).into(),
-		(foreign_asset_at_asset_hub_westend.clone(), asset_amount_to_send).into(),
+		(foreign_asset_at_asset_hub.clone(), asset_amount_to_send).into(),
 	]
 	.into();
 	let fee_asset_index = ah_assets
@@ -462,21 +448,17 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 	let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args);
 
 	let ah_sender_balance_before = ah_to_penpal.sender.balance;
-	let penpal_receiver_balance_before = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			system_para_native_asset_location.clone(),
-			&PenpalAReceiver::get(),
-		)
-	});
+	let penpal_receiver_balance_before = foreign_balance_on!(
+		PenpalA,
+		system_para_native_asset_location.clone(),
+		&PenpalAReceiver::get()
+	);
 
-	let ah_sender_assets_before = AssetHubWestend::execute_with(|| {
-		type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(),
-			&AssetHubWestendSender::get(),
-		)
-	});
+	let ah_sender_assets_before = foreign_balance_on!(
+		AssetHubWestend,
+		foreign_asset_at_asset_hub.clone(),
+		&AssetHubWestendSender::get()
+	);
 	let penpal_receiver_assets_before = PenpalA::execute_with(|| {
 		type Assets = <PenpalA as PenpalAPallet>::Assets;
 		<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
@@ -488,21 +470,14 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using
 	ah_to_penpal.assert();
 
 	let ah_sender_balance_after = ah_to_penpal.sender.balance;
-	let penpal_receiver_balance_after = PenpalA::execute_with(|| {
-		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			system_para_native_asset_location,
-			&PenpalAReceiver::get(),
-		)
-	});
+	let penpal_receiver_balance_after =
+		foreign_balance_on!(PenpalA, system_para_native_asset_location, &PenpalAReceiver::get());
 
-	let ah_sender_assets_after = AssetHubWestend::execute_with(|| {
-		type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
-		<ForeignAssets as Inspect<_>>::balance(
-			foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(),
-			&AssetHubWestendSender::get(),
-		)
-	});
+	let ah_sender_assets_after = foreign_balance_on!(
+		AssetHubWestend,
+		foreign_asset_at_asset_hub.clone(),
+		&AssetHubWestendSender::get()
+	);
 	let penpal_receiver_assets_after = PenpalA::execute_with(|| {
 		type Assets = <PenpalA as PenpalAPallet>::Assets;
 		<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
@@ -577,7 +552,7 @@ fn teleport_to_untrusted_chain_fails() {
 		]);
 		let result = <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::execute(
 			signed_origin,
-			bx!(xcm::VersionedXcm::V4(xcm)),
+			bx!(xcm::VersionedXcm::from(xcm)),
 			Weight::MAX,
 		);
 		assert!(result.is_err());
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
new file mode 100644
index 00000000000..3c53cfb261b
--- /dev/null
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs
@@ -0,0 +1,246 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{create_pool_with_wnd_on, foreign_balance_on, imports::*};
+use frame_support::traits::tokens::fungibles::Mutate;
+use xcm_builder::{DescribeAllTerminal, DescribeFamily, HashedDescription};
+use xcm_executor::traits::ConvertLocation;
+
+/// PenpalA transacts on PenpalB, paying fees using USDT. XCM has to go through Asset Hub as the
+/// reserve location of USDT. The original origin `PenpalA/PenpalASender` is proxied by Asset Hub.
+fn transfer_and_transact_in_same_xcm(
+	destination: Location,
+	usdt: Asset,
+	beneficiary: Location,
+	call: xcm::DoubleEncoded<()>,
+) {
+	let signed_origin = <PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get().into());
+	let context = PenpalUniversalLocation::get();
+	let asset_hub_location = PenpalA::sibling_location_of(AssetHubWestend::para_id());
+
+	let Fungible(total_usdt) = usdt.fun else { unreachable!() };
+
+	// TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get local fees, for now use hardcoded value.
+	let local_fees_amount = 80_000_000_000; // current exact value 69_200_786_622
+	let ah_fees_amount = 90_000_000_000; // current exact value 79_948_099_299
+	let usdt_to_ah_then_onward_amount = total_usdt - local_fees_amount - ah_fees_amount;
+
+	let local_fees: Asset = (usdt.id.clone(), local_fees_amount).into();
+	let fees_for_ah: Asset = (usdt.id.clone(), ah_fees_amount).into();
+	let usdt_to_ah_then_onward: Asset = (usdt.id.clone(), usdt_to_ah_then_onward_amount).into();
+
+	// xcm to be executed at dest
+	let xcm_on_dest = Xcm(vec![
+		Transact { origin_kind: OriginKind::Xcm, call },
+		ExpectTransactStatus(MaybeErrorCode::Success),
+		// since this is the last hop, we don't need to further use any assets previously
+		// reserved for fees (there are no further hops to cover transport fees for); we
+		// RefundSurplus to get back any unspent fees
+		RefundSurplus,
+		DepositAsset { assets: Wild(All), beneficiary },
+	]);
+	let destination = destination.reanchored(&asset_hub_location, &context).unwrap();
+	let xcm_on_ah = Xcm(vec![InitiateTransfer {
+		destination,
+		remote_fees: Some(AssetTransferFilter::ReserveDeposit(Wild(All))),
+		preserve_origin: true,
+		assets: vec![],
+		remote_xcm: xcm_on_dest,
+	}]);
+	let xcm = Xcm::<()>(vec![
+		WithdrawAsset(usdt.into()),
+		PayFees { asset: local_fees },
+		InitiateTransfer {
+			destination: asset_hub_location,
+			remote_fees: Some(AssetTransferFilter::ReserveWithdraw(fees_for_ah.into())),
+			preserve_origin: true,
+			assets: vec![AssetTransferFilter::ReserveWithdraw(usdt_to_ah_then_onward.into())],
+			remote_xcm: xcm_on_ah,
+		},
+	]);
+	<PenpalA as PenpalAPallet>::PolkadotXcm::execute(
+		signed_origin,
+		bx!(xcm::VersionedXcm::from(xcm.into())),
+		Weight::MAX,
+	)
+	.unwrap();
+}
+
+/// PenpalA transacts on PenpalB, paying fees using USDT. XCM has to go through Asset Hub as the
+/// reserve location of USDT. The original origin `PenpalA/PenpalASender` is proxied by Asset Hub.
+#[test]
+fn transact_from_para_to_para_through_asset_hub() {
+	let destination = PenpalA::sibling_location_of(PenpalB::para_id());
+	let sender = PenpalASender::get();
+	let fee_amount_to_send: Balance = WESTEND_ED * 10000;
+	let sender_chain_as_seen_by_asset_hub =
+		AssetHubWestend::sibling_location_of(PenpalA::para_id());
+	let sov_of_sender_on_asset_hub =
+		AssetHubWestend::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub);
+	let receiver_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalB::para_id());
+	let sov_of_receiver_on_asset_hub =
+		AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_asset_hub);
+
+	// Create SA-of-Penpal-on-AHW with ED.
+	AssetHubWestend::fund_accounts(vec![
+		(sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED),
+		(sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED),
+	]);
+
+	// Prefund USDT to sov account of sender.
+	AssetHubWestend::execute_with(|| {
+		type Assets = <AssetHubWestend as AssetHubWestendPallet>::Assets;
+		assert_ok!(<Assets as Mutate<_>>::mint_into(
+			USDT_ID,
+			&sov_of_sender_on_asset_hub.clone().into(),
+			fee_amount_to_send,
+		));
+	});
+
+	// We create a pool between WND and USDT in AssetHub.
+	let usdt = Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]);
+	create_pool_with_wnd_on!(AssetHubWestend, usdt, false, AssetHubWestendSender::get());
+	// We also need a pool between WND and USDT on PenpalA.
+	create_pool_with_wnd_on!(PenpalA, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get());
+	// We also need a pool between WND and USDT on PenpalB.
+	create_pool_with_wnd_on!(PenpalB, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get());
+
+	let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get();
+	PenpalA::execute_with(|| {
+		type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
+		assert_ok!(<ForeignAssets as Mutate<_>>::mint_into(
+			usdt_from_asset_hub.clone(),
+			&sender,
+			fee_amount_to_send,
+		));
+	});
+
+	// Give the sender enough Relay tokens to pay for local delivery fees.
+	PenpalA::mint_foreign_asset(
+		<PenpalA as Chain>::RuntimeOrigin::signed(PenpalAssetOwner::get()),
+		RelayLocation::get(),
+		sender.clone(),
+		10_000_000_000_000, // Large estimate to make sure it works.
+	);
+
+	// Init values for Parachain Destination
+	let receiver = PenpalBReceiver::get();
+
+	// Query initial balances
+	let sender_assets_before = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender);
+	let receiver_assets_before =
+		foreign_balance_on!(PenpalB, usdt_from_asset_hub.clone(), &receiver);
+
+	// Now register a new asset on PenpalB from PenpalA/sender account while paying fees using USDT
+	// (going through Asset Hub)
+
+	let usdt_to_send: Asset = (usdt_from_asset_hub.clone(), fee_amount_to_send).into();
+	let assets: Assets = usdt_to_send.clone().into();
+	let asset_location_on_penpal_a =
+		Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())]);
+	let penpal_a_as_seen_by_penpal_b = PenpalB::sibling_location_of(PenpalA::para_id());
+	let sender_as_seen_by_penpal_b =
+		penpal_a_as_seen_by_penpal_b.clone().appended_with(sender.clone()).unwrap();
+	let foreign_asset_at_penpal_b =
+		penpal_a_as_seen_by_penpal_b.appended_with(asset_location_on_penpal_a).unwrap();
+	// Encoded `create_asset` call to be executed in PenpalB
+	let call = PenpalB::create_foreign_asset_call(
+		foreign_asset_at_penpal_b.clone(),
+		ASSET_MIN_BALANCE,
+		receiver.clone(),
+	);
+	PenpalA::execute_with(|| {
+		// initiate transaction
+		transfer_and_transact_in_same_xcm(destination, usdt_to_send, receiver.clone().into(), call);
+
+		// verify expected events;
+		PenpalA::assert_xcm_pallet_attempted_complete(None);
+	});
+	AssetHubWestend::execute_with(|| {
+		let sov_penpal_a_on_ah = AssetHubWestend::sovereign_account_id_of(
+			AssetHubWestend::sibling_location_of(PenpalA::para_id()),
+		);
+		let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of(
+			AssetHubWestend::sibling_location_of(PenpalB::para_id()),
+		);
+		asset_hub_hop_assertions(&assets, sov_penpal_a_on_ah, sov_penpal_b_on_ah);
+	});
+	PenpalB::execute_with(|| {
+		let expected_creator =
+			HashedDescription::<AccountId, DescribeFamily<DescribeAllTerminal>>::convert_location(
+				&sender_as_seen_by_penpal_b,
+			)
+			.unwrap();
+		penpal_b_assertions(foreign_asset_at_penpal_b, expected_creator, receiver.clone());
+	});
+
+	// Query final balances
+	let sender_assets_after = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender);
+	let receiver_assets_after = foreign_balance_on!(PenpalB, usdt_from_asset_hub, &receiver);
+
+	// Sender's balance is reduced by amount
+	assert_eq!(sender_assets_after, sender_assets_before - fee_amount_to_send);
+	// Receiver's balance is increased
+	assert!(receiver_assets_after > receiver_assets_before);
+}
+
+fn asset_hub_hop_assertions(assets: &Assets, sender_sa: AccountId, receiver_sa: AccountId) {
+	type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
+	for asset in assets.inner() {
+		let amount = if let Fungible(a) = asset.fun { a } else { unreachable!() };
+		assert_expected_events!(
+			AssetHubWestend,
+			vec![
+				// Withdrawn from sender parachain SA
+				RuntimeEvent::Assets(
+					pallet_assets::Event::Burned { owner, balance, .. }
+				) => {
+					owner: *owner == sender_sa,
+					balance: *balance == amount,
+				},
+				// Deposited to receiver parachain SA
+				RuntimeEvent::Assets(
+					pallet_assets::Event::Deposited { who, .. }
+				) => {
+					who: *who == receiver_sa,
+				},
+				RuntimeEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+			]
+		);
+	}
+}
+
+fn penpal_b_assertions(
+	expected_asset: Location,
+	expected_creator: AccountId,
+	expected_owner: AccountId,
+) {
+	type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
+	PenpalB::assert_xcmp_queue_success(None);
+	assert_expected_events!(
+		PenpalB,
+		vec![
+			RuntimeEvent::ForeignAssets(
+				pallet_assets::Event::Created { asset_id, creator, owner }
+			) => {
+				asset_id: *asset_id == expected_asset,
+				creator: *creator == expected_creator,
+				owner: *owner == expected_owner,
+			},
+		]
+	);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs
index b7096718438..c303e6411d3 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs
@@ -32,11 +32,10 @@ fn create_and_claim_treasury_spend() {
 		ahw_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap();
 	let asset_hub_location = Location::new(0, Parachain(AssetHubWestend::para_id().into()));
 	let root = <Westend as Chain>::RuntimeOrigin::root();
-	// asset kind to be spend from the treasury.
-	let asset_kind = VersionedLocatableAsset::V4 {
-		location: asset_hub_location,
-		asset_id: AssetId([PalletInstance(50), GeneralIndex(USDT_ID.into())].into()),
-	};
+	// asset kind to be spent from the treasury.
+	let asset_kind: VersionedLocatableAsset =
+		(asset_hub_location, AssetId([PalletInstance(50), GeneralIndex(USDT_ID.into())].into()))
+			.into();
 	// treasury spend beneficiary.
 	let alice: AccountId = Westend::account_id_of(ALICE);
 	let bob: AccountId = Westend::account_id_of(BOB);
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs
index 037d6604ea4..ec05a074c5a 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs
@@ -17,10 +17,8 @@
 
 use crate::imports::*;
 
-use frame_support::{
-	dispatch::RawOrigin,
-	sp_runtime::{traits::Dispatchable, DispatchResult},
-};
+use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees;
+use frame_support::dispatch::RawOrigin;
 use xcm_runtime_apis::{
 	dry_run::runtime_decl_for_dry_run_api::DryRunApiV1,
 	fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1,
@@ -77,22 +75,12 @@ fn receiver_assertions(test: ParaToParaThroughAHTest) {
 	);
 }
 
-fn transfer_assets_para_to_para_through_ah_dispatchable(
-	test: ParaToParaThroughAHTest,
-) -> DispatchResult {
-	let call = transfer_assets_para_to_para_through_ah_call(test.clone());
-	match call.dispatch(test.signed_origin) {
-		Ok(_) => Ok(()),
-		Err(error_with_post_info) => Err(error_with_post_info.error),
-	}
-}
-
 fn transfer_assets_para_to_para_through_ah_call(
 	test: ParaToParaThroughAHTest,
 ) -> <PenpalA as Chain>::RuntimeCall {
 	type RuntimeCall = <PenpalA as Chain>::RuntimeCall;
 
-	let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id());
+	let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubWestend::para_id());
 	let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset {
 		assets: Wild(AllCounted(test.args.assets.len() as u32)),
 		beneficiary: test.args.beneficiary,
@@ -101,7 +89,7 @@ fn transfer_assets_para_to_para_through_ah_call(
 		dest: bx!(test.args.dest.into()),
 		assets: bx!(test.args.assets.clone().into()),
 		assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())),
-		remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))),
+		remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::parent()))),
 		fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())),
 		custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)),
 		weight_limit: test.args.weight_limit,
@@ -153,7 +141,7 @@ fn multi_hop_works() {
 
 	// We get them from the PenpalA closure.
 	let mut delivery_fees_amount = 0;
-	let mut remote_message = VersionedXcm::V4(Xcm(Vec::new()));
+	let mut remote_message = VersionedXcm::from(Xcm(Vec::new()));
 	<PenpalA as TestExt>::execute_with(|| {
 		type Runtime = <PenpalA as Chain>::Runtime;
 		type OriginCaller = <PenpalA as Chain>::OriginCaller;
@@ -166,7 +154,7 @@ fn multi_hop_works() {
 			.forwarded_xcms
 			.iter()
 			.find(|(destination, _)| {
-				*destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)]))
+				*destination == VersionedLocation::from(Location::new(1, [Parachain(1000)]))
 			})
 			.unwrap();
 		assert_eq!(messages_to_query.len(), 1);
@@ -180,7 +168,7 @@ fn multi_hop_works() {
 	// These are set in the AssetHub closure.
 	let mut intermediate_execution_fees = 0;
 	let mut intermediate_delivery_fees_amount = 0;
-	let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new()));
+	let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new()));
 	<AssetHubWestend as TestExt>::execute_with(|| {
 		type Runtime = <AssetHubWestend as Chain>::Runtime;
 		type RuntimeCall = <AssetHubWestend as Chain>::RuntimeCall;
@@ -189,13 +177,14 @@ fn multi_hop_works() {
 		let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap();
 		intermediate_execution_fees = Runtime::query_weight_to_asset_fee(
 			weight,
-			VersionedAssetId::V4(Location::new(1, []).into()),
+			VersionedAssetId::from(AssetId(Location::new(1, []))),
 		)
 		.unwrap();
 
 		// We have to do this to turn `VersionedXcm<()>` into `VersionedXcm<RuntimeCall>`.
-		let xcm_program =
-			VersionedXcm::V4(Xcm::<RuntimeCall>::from(remote_message.clone().try_into().unwrap()));
+		let xcm_program = VersionedXcm::from(Xcm::<RuntimeCall>::from(
+			remote_message.clone().try_into().unwrap(),
+		));
 
 		// Now we get the delivery fees to the final destination.
 		let result =
@@ -204,7 +193,7 @@ fn multi_hop_works() {
 			.forwarded_xcms
 			.iter()
 			.find(|(destination, _)| {
-				*destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)]))
+				*destination == VersionedLocation::from(Location::new(1, [Parachain(2001)]))
 			})
 			.unwrap();
 		// There's actually two messages here.
@@ -228,7 +217,7 @@ fn multi_hop_works() {
 
 		let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap();
 		final_execution_fees =
-			Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into()))
+			Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(Location::parent()))
 				.unwrap();
 	});
 
@@ -259,7 +248,8 @@ fn multi_hop_works() {
 	test.set_assertion::<PenpalA>(sender_assertions);
 	test.set_assertion::<AssetHubWestend>(hop_assertions);
 	test.set_assertion::<PenpalB>(receiver_assertions);
-	test.set_dispatchable::<PenpalA>(transfer_assets_para_to_para_through_ah_dispatchable);
+	let call = transfer_assets_para_to_para_through_ah_call(test.clone());
+	test.set_call(call);
 	test.assert();
 
 	let sender_assets_after = PenpalA::execute_with(|| {
@@ -286,3 +276,14 @@ fn multi_hop_works() {
 			final_execution_fees
 	);
 }
+
+#[test]
+fn multi_hop_pay_fees_works() {
+	test_can_estimate_and_pay_exact_fees!(
+		PenpalA,
+		AssetHubWestend,
+		PenpalB,
+		(Parent, 1_000_000_000_000u128),
+		Penpal
+	);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
index 77e4c8183e6..54bc395c86f 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
@@ -22,9 +22,8 @@ mod imports {
 
 	// Polkadot
 	pub use xcm::{
-		latest::ParentThen,
+		latest::{ParentThen, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH},
 		prelude::{AccountId32 as AccountId32Junction, *},
-		v4::{self, NetworkId::Westend as WestendId},
 	};
 	pub use xcm_executor::traits::TransferType;
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs
index 0e1cfdd82aa..33ab1e70b97 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs
@@ -39,7 +39,7 @@ fn send_assets_over_bridge<F: FnOnce()>(send_fn: F) {
 fn set_up_rocs_for_penpal_rococo_through_ahr_to_ahw(
 	sender: &AccountId,
 	amount: u128,
-) -> (Location, v4::Location) {
+) -> (Location, v5::Location) {
 	let roc_at_rococo_parachains = roc_at_ah_rococo();
 	let roc_at_asset_hub_westend = bridged_roc_at_ah_westend();
 	create_foreign_on_ah_westend(roc_at_asset_hub_westend.clone(), true);
@@ -70,7 +70,7 @@ fn send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah(
 		);
 		let sov_ahw_on_ahr =
 			AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-				Westend,
+				ByGenesis(WESTEND_GENESIS_HASH),
 				AssetHubWestend::para_id(),
 			);
 		// send message over bridge
@@ -125,7 +125,7 @@ fn send_roc_from_asset_hub_rococo_to_asset_hub_westend() {
 	set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true);
 
 	let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		AssetHubWestend::para_id(),
 	);
 	let rocs_in_reserve_on_ahr_before =
@@ -199,7 +199,7 @@ fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() {
 
 	// fund the AHR's SA on AHW with the WND tokens held in reserve
 	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-		Rococo,
+		ByGenesis(ROCOCO_GENESIS_HASH),
 		AssetHubRococo::para_id(),
 	);
 	AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]);
@@ -271,7 +271,7 @@ fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() {
 	create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true);
 	// prefund AHR's sovereign account on AHW to be able to withdraw USDT and wETH from reserves
 	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-		Rococo,
+		ByGenesis(ROCOCO_GENESIS_HASH),
 		AssetHubRococo::para_id(),
 	);
 	AssetHubWestend::mint_asset(
@@ -357,7 +357,7 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend()
 		set_up_rocs_for_penpal_rococo_through_ahr_to_ahw(&sender, amount);
 
 	let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		AssetHubWestend::para_id(),
 	);
 	let rocs_in_reserve_on_ahr_before =
@@ -463,7 +463,7 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste
 
 	// fund the AHR's SA on AHW with the WND tokens held in reserve
 	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-		NetworkId::Rococo,
+		NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
 		AssetHubRococo::para_id(),
 	);
 	AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), amount * 2)]);
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs
index e61dc35bdf8..e678cc40a3c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = BridgeHubRococoExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount);
+	test_chain_can_claim_assets!(
+		AssetHubRococo,
+		RuntimeCall,
+		NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs
index 767f74f6ad7..8aff8775596 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 use crate::imports::*;
+use xcm::opaque::v5;
 
 mod asset_transfers;
 mod claim_assets;
@@ -23,10 +24,22 @@ mod snowbridge;
 mod teleport;
 
 pub(crate) fn asset_hub_westend_location() -> Location {
-	Location::new(2, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())])
+	Location::new(
+		2,
+		[
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+			Parachain(AssetHubWestend::para_id().into()),
+		],
+	)
 }
 pub(crate) fn bridge_hub_westend_location() -> Location {
-	Location::new(2, [GlobalConsensus(Westend), Parachain(BridgeHubWestend::para_id().into())])
+	Location::new(
+		2,
+		[
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+			Parachain(BridgeHubWestend::para_id().into()),
+		],
+	)
 }
 
 // ROC and wROC
@@ -34,7 +47,7 @@ pub(crate) fn roc_at_ah_rococo() -> Location {
 	Parent.into()
 }
 pub(crate) fn bridged_roc_at_ah_westend() -> Location {
-	Location::new(2, [GlobalConsensus(Rococo)])
+	Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))])
 }
 
 // WND and wWND
@@ -42,7 +55,7 @@ pub(crate) fn wnd_at_ah_westend() -> Location {
 	Parent.into()
 }
 pub(crate) fn bridged_wnd_at_ah_rococo() -> Location {
-	Location::new(2, [GlobalConsensus(Westend)])
+	Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))])
 }
 
 // USDT and wUSDT
@@ -53,7 +66,7 @@ pub(crate) fn bridged_usdt_at_ah_rococo() -> Location {
 	Location::new(
 		2,
 		[
-			GlobalConsensus(Westend),
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 			Parachain(AssetHubWestend::para_id().into()),
 			PalletInstance(ASSETS_PALLET_ID),
 			GeneralIndex(USDT_ID.into()),
@@ -73,7 +86,7 @@ pub(crate) fn weth_at_asset_hubs() -> Location {
 }
 
 pub(crate) fn create_foreign_on_ah_rococo(
-	id: v4::Location,
+	id: v5::Location,
 	sufficient: bool,
 	prefund_accounts: Vec<(AccountId, u128)>,
 ) {
@@ -82,18 +95,18 @@ pub(crate) fn create_foreign_on_ah_rococo(
 	AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts);
 }
 
-pub(crate) fn create_foreign_on_ah_westend(id: v4::Location, sufficient: bool) {
+pub(crate) fn create_foreign_on_ah_westend(id: v5::Location, sufficient: bool) {
 	let owner = AssetHubWestend::account_id_of(ALICE);
 	AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]);
 }
 
-pub(crate) fn foreign_balance_on_ah_rococo(id: v4::Location, who: &AccountId) -> u128 {
+pub(crate) fn foreign_balance_on_ah_rococo(id: v5::Location, who: &AccountId) -> u128 {
 	AssetHubRococo::execute_with(|| {
 		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
 		<Assets as Inspect<_>>::balance(id, who)
 	})
 }
-pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 {
+pub(crate) fn foreign_balance_on_ah_westend(id: v5::Location, who: &AccountId) -> u128 {
 	AssetHubWestend::execute_with(|| {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
 		<Assets as Inspect<_>>::balance(id, who)
@@ -101,8 +114,8 @@ pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -
 }
 
 // set up pool
-pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v4::Location, is_foreign: bool) {
-	let wnd: v4::Location = v4::Parent.into();
+pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v5::Location, is_foreign: bool) {
+	let wnd: v5::Location = v5::Parent.into();
 	AssetHubWestend::execute_with(|| {
 		type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
 		let owner = AssetHubWestendSender::get();
@@ -117,7 +130,7 @@ pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v4::Location, is_foreign
 			));
 		} else {
 			let asset_id = match asset.interior.last() {
-				Some(v4::Junction::GeneralIndex(id)) => *id as u32,
+				Some(GeneralIndex(id)) => *id as u32,
 				_ => unreachable!(),
 			};
 			assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::Assets::mint(
@@ -237,7 +250,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() {
 	BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5);
 	AssetHubRococo::open_bridge(
 		AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()),
-		[GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(),
+		[
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+			Parachain(AssetHubWestend::para_id().into()),
+		]
+		.into(),
 		Some((
 			(roc_at_ah_rococo(), ROC * 1).into(),
 			BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of(
@@ -250,7 +267,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() {
 	BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5);
 	AssetHubWestend::open_bridge(
 		AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()),
-		[GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(),
+		[
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
+			Parachain(AssetHubRococo::para_id().into()),
+		]
+		.into(),
 		Some((
 			(wnd_at_ah_westend(), WND * 1).into(),
 			BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of(
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs
index 44637670112..1ae3a1b1580 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs
@@ -22,7 +22,7 @@ const XCM_FEE: u128 = 4_000_000_000_000;
 fn register_rococo_asset_on_wah_from_rah() {
 	let sa_of_rah_on_wah =
 		AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-			Rococo,
+			ByGenesis(ROCOCO_GENESIS_HASH),
 			AssetHubRococo::para_id(),
 		);
 
@@ -30,7 +30,7 @@ fn register_rococo_asset_on_wah_from_rah() {
 	let bridged_asset_at_wah = Location::new(
 		2,
 		[
-			GlobalConsensus(Rococo),
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
 			Parachain(AssetHubRococo::para_id().into()),
 			PalletInstance(ASSETS_PALLET_ID),
 			GeneralIndex(ASSET_ID.into()),
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
index 12f05742a08..931a3128f82 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs
@@ -29,7 +29,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable
 	let xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit, check_origin },
 		ExportMessage {
-			network: WestendId,
+			network: ByGenesis(WESTEND_GENESIS_HASH),
 			destination: [Parachain(AssetHubWestend::para_id().into())].into(),
 			xcm: remote_xcm,
 		},
@@ -60,15 +60,6 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable
 
 #[test]
 fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
-	// Initially set only default version on all runtimes
-	let newer_xcm_version = xcm::prelude::XCM_VERSION;
-	let older_xcm_version = newer_xcm_version - 1;
-
-	AssetHubRococo::force_default_xcm_version(Some(older_xcm_version));
-	BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version));
-	BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version));
-	AssetHubWestend::force_default_xcm_version(Some(older_xcm_version));
-
 	// prepare data
 	let destination = asset_hub_westend_location();
 	let native_token = Location::parent();
@@ -82,6 +73,14 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
 	// open bridge
 	open_bridge_between_asset_hub_rococo_and_asset_hub_westend();
 
+	// Initially set only default version on all runtimes
+	let newer_xcm_version = xcm::prelude::XCM_VERSION;
+	let older_xcm_version = newer_xcm_version - 1;
+	AssetHubRococo::force_default_xcm_version(Some(older_xcm_version));
+	BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version));
+	BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version));
+	AssetHubWestend::force_default_xcm_version(Some(older_xcm_version));
+
 	// send XCM from AssetHubRococo - fails - destination version not known
 	assert_err!(
 		send_assets_from_asset_hub_rococo(
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
index 912e74af698..d59553574c2 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
@@ -84,11 +84,7 @@ fn create_agent() {
 	let remote_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact {
-			require_weight_at_most: 3000000000.into(),
-			origin_kind: OriginKind::Xcm,
-			call: create_agent_call.encode().into(),
-		},
+		Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() },
 	]));
 
 	// Rococo Global Consensus
@@ -142,11 +138,7 @@ fn create_channel() {
 	let create_agent_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact {
-			require_weight_at_most: 3000000000.into(),
-			origin_kind: OriginKind::Xcm,
-			call: create_agent_call.encode().into(),
-		},
+		Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() },
 	]));
 
 	let create_channel_call =
@@ -155,11 +147,7 @@ fn create_channel() {
 	let create_channel_xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 		DescendOrigin(Parachain(origin_para).into()),
-		Transact {
-			require_weight_at_most: 3000000000.into(),
-			origin_kind: OriginKind::Xcm,
-			call: create_channel_call.encode().into(),
-		},
+		Transact { origin_kind: OriginKind::Xcm, call: create_channel_call.encode().into() },
 	]));
 
 	// Rococo Global Consensus
@@ -310,11 +298,13 @@ fn send_token_from_ethereum_to_penpal() {
 		));
 	});
 
+	let ethereum_network_v5: NetworkId = EthereumNetwork::get().into();
+
 	// The Weth asset location, identified by the contract address on Ethereum
 	let weth_asset_location: Location =
-		(Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into();
+		(Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into();
 
-	let origin_location = (Parent, Parent, EthereumNetwork::get()).into();
+	let origin_location = (Parent, Parent, ethereum_network_v5).into();
 
 	// Fund ethereum sovereign on AssetHub
 	let ethereum_sovereign: AccountId =
@@ -323,10 +313,11 @@ fn send_token_from_ethereum_to_penpal() {
 
 	// Create asset on the Penpal parachain.
 	PenpalA::execute_with(|| {
-		assert_ok!(<PenpalA as PenpalAPallet>::ForeignAssets::create(
-			<PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get()),
+		assert_ok!(<PenpalA as PenpalAPallet>::ForeignAssets::force_create(
+			<PenpalA as Chain>::RuntimeOrigin::root(),
 			weth_asset_location.clone(),
 			asset_hub_sovereign.into(),
+			false,
 			1000,
 		));
 
@@ -447,14 +438,14 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
 			)),
 			fun: Fungible(WETH_AMOUNT),
 		}];
-		let multi_assets = VersionedAssets::V4(Assets::from(assets));
+		let multi_assets = VersionedAssets::from(Assets::from(assets));
 
-		let destination = VersionedLocation::V4(Location::new(
+		let destination = VersionedLocation::from(Location::new(
 			2,
 			[GlobalConsensus(Ethereum { chain_id: CHAIN_ID })],
 		));
 
-		let beneficiary = VersionedLocation::V4(Location::new(
+		let beneficiary = VersionedLocation::from(Location::new(
 			0,
 			[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
 		));
@@ -563,10 +554,9 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() {
 }
 
 fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) {
-	let weth_asset_location: Location = Location::new(
-		2,
-		[EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }],
-	);
+	let ethereum_network_v5: NetworkId = EthereumNetwork::get().into();
+	let weth_asset_location: Location =
+		Location::new(2, [ethereum_network_v5.into(), AccountKey20 { network: None, key: WETH }]);
 	// Fund asset hub sovereign on bridge hub
 	let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new(
 		1,
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs
index 76e8312921d..501ddb84d42 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs
@@ -22,9 +22,9 @@ mod imports {
 
 	// Polkadot
 	pub use xcm::{
-		latest::ParentThen,
+		latest::{ParentThen, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH},
 		prelude::{AccountId32 as AccountId32Junction, *},
-		v4::{self, NetworkId::Rococo as RococoId},
+		v5,
 	};
 	pub use xcm_executor::traits::TransferType;
 
@@ -56,6 +56,7 @@ mod imports {
 		penpal_emulated_chain::{
 			penpal_runtime::xcm_config::{
 				CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub,
+				LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub,
 				UniversalLocation as PenpalUniversalLocation,
 			},
 			PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet,
@@ -71,8 +72,9 @@ mod imports {
 		BridgeHubWestendPara as BridgeHubWestend,
 		BridgeHubWestendParaReceiver as BridgeHubWestendReceiver,
 		BridgeHubWestendParaSender as BridgeHubWestendSender, PenpalBPara as PenpalB,
-		PenpalBParaSender as PenpalBSender, WestendRelay as Westend,
-		WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender,
+		PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender,
+		WestendRelay as Westend, WestendRelayReceiver as WestendReceiver,
+		WestendRelaySender as WestendSender,
 	};
 
 	pub const ASSET_ID: u32 = 1;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs
index 0856c952600..ab09517339d 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs
@@ -12,7 +12,9 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-use crate::tests::*;
+
+use crate::{create_pool_with_native_on, tests::*};
+use xcm::latest::AssetTransferFilter;
 
 fn send_assets_over_bridge<F: FnOnce()>(send_fn: F) {
 	// fund the AHW's SA on BHW for paying bridge transport fees
@@ -38,7 +40,7 @@ fn send_assets_over_bridge<F: FnOnce()>(send_fn: F) {
 fn set_up_wnds_for_penpal_westend_through_ahw_to_ahr(
 	sender: &AccountId,
 	amount: u128,
-) -> (Location, v4::Location) {
+) -> (Location, v5::Location) {
 	let wnd_at_westend_parachains = wnd_at_ah_westend();
 	let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo();
 	create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), true);
@@ -69,10 +71,9 @@ fn send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah(
 		);
 		let sov_ahr_on_ahw =
 			AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-				Rococo,
+				ByGenesis(ROCOCO_GENESIS_HASH),
 				AssetHubRococo::para_id(),
 			);
-
 		// send message over bridge
 		assert_ok!(PenpalB::execute_with(|| {
 			let signed_origin = <PenpalB as Chain>::RuntimeOrigin::signed(PenpalBSender::get());
@@ -128,13 +129,18 @@ fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() {
 	let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo();
 
 	create_foreign_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true);
-	set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true);
+	create_pool_with_native_on!(
+		AssetHubRococo,
+		bridged_wnd_at_asset_hub_rococo.clone(),
+		true,
+		AssetHubRococoSender::get()
+	);
 
 	////////////////////////////////////////////////////////////
 	// Let's first send over just some WNDs as a simple example
 	////////////////////////////////////////////////////////////
 	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-		Rococo,
+		ByGenesis(ROCOCO_GENESIS_HASH),
 		AssetHubRococo::para_id(),
 	);
 	let wnds_in_reserve_on_ahw_before =
@@ -206,7 +212,12 @@ fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() {
 	);
 	create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true);
 	create_foreign_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true);
-	set_up_pool_with_roc_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true);
+	create_pool_with_native_on!(
+		AssetHubRococo,
+		bridged_usdt_at_asset_hub_rococo.clone(),
+		true,
+		AssetHubRococoSender::get()
+	);
 
 	let receiver_usdts_before =
 		foreign_balance_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), &receiver);
@@ -269,7 +280,7 @@ fn send_back_rocs_from_asset_hub_westend_to_asset_hub_rococo() {
 
 	// fund the AHW's SA on AHR with the ROC tokens held in reserve
 	let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		AssetHubWestend::para_id(),
 	);
 	AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), prefund_amount)]);
@@ -339,7 +350,7 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo()
 		set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount);
 
 	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
-		Rococo,
+		ByGenesis(ROCOCO_GENESIS_HASH),
 		AssetHubRococo::para_id(),
 	);
 	let wnds_in_reserve_on_ahw_before =
@@ -445,7 +456,7 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc
 
 	// fund the AHW's SA on AHR with the ROC tokens held in reserve
 	let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		AssetHubWestend::para_id(),
 	);
 	AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), amount * 2)]);
@@ -543,3 +554,295 @@ fn dry_run_transfer_to_rococo_sends_xcm_to_bridge_hub() {
 		asset_hub_rococo_location()
 	);
 }
+
+fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
+	wnds: (Location, u128),
+	pens: (Location, u128),
+) {
+	let (wnds_id, wnds_amount) = wnds;
+	let (pens_id, pens_amount) = pens;
+	send_assets_over_bridge(|| {
+		let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(
+			AssetHubWestend::sibling_location_of(PenpalB::para_id()),
+		);
+		let sov_ahr_on_ahw =
+			AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
+				ByGenesis(ROCOCO_GENESIS_HASH),
+				AssetHubRococo::para_id(),
+			);
+		// send message over bridge
+		assert_ok!(PenpalB::execute_with(|| {
+			let destination = asset_hub_rococo_location();
+			let local_asset_hub = PenpalB::sibling_location_of(AssetHubWestend::para_id());
+			let signed_origin = <PenpalB as Chain>::RuntimeOrigin::signed(PenpalBSender::get());
+			let beneficiary: Location =
+				AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }
+					.into();
+			let wnds: Asset = (wnds_id.clone(), wnds_amount).into();
+			let pens: Asset = (pens_id, pens_amount).into();
+			let assets: Assets = vec![wnds.clone(), pens.clone()].into();
+
+			// TODO: dry-run to get exact fees, for now just some static value 100_000_000_000
+			let penpal_fees_amount = 100_000_000_000;
+			// use 100_000_000_000 WNDs in fees on AHW
+			// (exec fees: 3_593_000_000, transpo fees: 69_021_561_290 = 72_614_561_290)
+			// TODO: make this exact once we have bridge dry-running
+			let ahw_fee_amount = 100_000_000_000;
+
+			// XCM to be executed at dest (Rococo Asset Hub)
+			let xcm_on_dest = Xcm(vec![
+				// since this is the last hop, we don't need to further use any assets previously
+				// reserved for fees (there are no further hops to cover transport fees for); we
+				// RefundSurplus to get back any unspent fees
+				RefundSurplus,
+				// deposit everything to final beneficiary
+				DepositAsset { assets: Wild(All), beneficiary: beneficiary.clone() },
+			]);
+
+			// XCM to be executed at (intermediary) Westend Asset Hub
+			let context = PenpalUniversalLocation::get();
+			let reanchored_dest =
+				destination.clone().reanchored(&local_asset_hub, &context).unwrap();
+			let reanchored_pens = pens.clone().reanchored(&local_asset_hub, &context).unwrap();
+			let mut onward_wnds = wnds.clone().reanchored(&local_asset_hub, &context).unwrap();
+			onward_wnds.fun = Fungible(wnds_amount - ahw_fee_amount - penpal_fees_amount);
+			let xcm_on_ahw = Xcm(vec![
+				// both WNDs and PENs are local-reserve transferred to Rococo Asset Hub
+				// initially, all WNDs are reserved for fees on destination, but at the end of the
+				// program we RefundSurplus to get back any unspent and deposit them to final
+				// beneficiary
+				InitiateTransfer {
+					destination: reanchored_dest,
+					remote_fees: Some(AssetTransferFilter::ReserveDeposit(onward_wnds.into())),
+					preserve_origin: false,
+					assets: vec![AssetTransferFilter::ReserveDeposit(reanchored_pens.into())],
+					remote_xcm: xcm_on_dest,
+				},
+			]);
+
+			let penpal_fees = (wnds.id.clone(), Fungible(penpal_fees_amount));
+			let ahw_fees: Asset = (wnds.id.clone(), Fungible(ahw_fee_amount)).into();
+			let ahw_non_fees_wnds: Asset =
+				(wnds.id.clone(), Fungible(wnds_amount - ahw_fee_amount - penpal_fees_amount))
+					.into();
+			// XCM to be executed locally
+			let xcm = Xcm::<()>(vec![
+				// Withdraw both WNDs and PENs from origin account
+				WithdrawAsset(assets.into()),
+				PayFees { asset: penpal_fees.into() },
+				// Execute the transfers while paying remote fees with WNDs
+				InitiateTransfer {
+					destination: local_asset_hub,
+					// WNDs for fees are reserve-withdrawn at AHW and reserved for fees
+					remote_fees: Some(AssetTransferFilter::ReserveWithdraw(ahw_fees.into())),
+					preserve_origin: false,
+					// PENs are teleported to AHW, rest of non-fee WNDs are reserve-withdrawn at AHW
+					assets: vec![
+						AssetTransferFilter::Teleport(pens.into()),
+						AssetTransferFilter::ReserveWithdraw(ahw_non_fees_wnds.into()),
+					],
+					remote_xcm: xcm_on_ahw,
+				},
+			]);
+
+			<PenpalB as PenpalBPallet>::PolkadotXcm::execute(
+				signed_origin,
+				bx!(xcm::VersionedXcm::V5(xcm.into())),
+				Weight::MAX,
+			)
+		}));
+		AssetHubWestend::execute_with(|| {
+			type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
+			assert_expected_events!(
+				AssetHubWestend,
+				vec![
+					// Amount to reserve transfer is withdrawn from Penpal's sovereign account
+					RuntimeEvent::Balances(
+						pallet_balances::Event::Burned { who, amount }
+					) => {
+						who: *who == sov_penpal_on_ahw.clone().into(),
+						amount: *amount == wnds_amount,
+					},
+					// Amount deposited in AHR's sovereign account
+					RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => {
+						who: *who == sov_ahr_on_ahw.clone().into(),
+					},
+					RuntimeEvent::XcmpQueue(
+						cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }
+					) => {},
+				]
+			);
+		});
+	});
+}
+
+/// Transfer "PEN"s plus "WND"s from PenpalWestend to AssetHubWestend, over bridge to
+/// AssetHubRococo. PENs need to be teleported to AHW, while WNDs reserve-withdrawn, then both
+/// reserve transferred further to AHR. (transfer 2 different assets with different transfer types
+/// across 3 different chains)
+#[test]
+fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() {
+	let penpal_check_account = <PenpalB as PenpalBPallet>::PolkadotXcm::check_account();
+	let owner: AccountId = AssetHubRococo::account_id_of(ALICE);
+	let sender = PenpalBSender::get();
+	let amount = ASSET_HUB_WESTEND_ED * 10_000_000;
+
+	let (wnd_at_westend_parachains, wnd_at_rococo_parachains) =
+		set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount);
+
+	let pens_location_on_penpal =
+		Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap();
+	let pens_id_on_penpal = match pens_location_on_penpal.last() {
+		Some(Junction::GeneralIndex(id)) => *id as u32,
+		_ => unreachable!(),
+	};
+
+	let penpal_parachain_junction = Junction::Parachain(PenpalB::para_id().into());
+	let pens_at_ahw = Location::new(
+		1,
+		pens_location_on_penpal
+			.interior()
+			.clone()
+			.pushed_front_with(penpal_parachain_junction)
+			.unwrap(),
+	);
+	let pens_at_rococo_parachains = Location::new(
+		2,
+		pens_at_ahw
+			.interior()
+			.clone()
+			.pushed_front_with(Junction::GlobalConsensus(NetworkId::ByGenesis(
+				WESTEND_GENESIS_HASH,
+			)))
+			.unwrap(),
+	);
+	let wnds_to_send = amount;
+	let pens_to_send = amount;
+
+	// ---------- Set up Penpal Westend ----------
+	// Fund Penpal's sender account. No need to create the asset (only mint), it exists in genesis.
+	PenpalB::mint_asset(
+		<PenpalB as Chain>::RuntimeOrigin::signed(owner.clone()),
+		pens_id_on_penpal,
+		sender.clone(),
+		pens_to_send * 2,
+	);
+	// fund Penpal's check account to be able to teleport
+	PenpalB::fund_accounts(vec![(penpal_check_account.clone().into(), pens_to_send * 2)]);
+
+	// ---------- Set up Asset Hub Rococo ----------
+	// create PEN at AHR
+	AssetHubRococo::force_create_foreign_asset(
+		pens_at_rococo_parachains.clone(),
+		owner.clone(),
+		false,
+		ASSET_MIN_BALANCE,
+		vec![],
+	);
+
+	// account balances before
+	let sender_wnds_before = PenpalB::execute_with(|| {
+		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
+		<ForeignAssets as Inspect<_>>::balance(
+			wnd_at_westend_parachains.clone().into(),
+			&PenpalBSender::get(),
+		)
+	});
+	let sender_pens_before = PenpalB::execute_with(|| {
+		type Assets = <PenpalB as PenpalBPallet>::Assets;
+		<Assets as Inspect<_>>::balance(pens_id_on_penpal, &PenpalBSender::get())
+	});
+	let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus(
+		ByGenesis(ROCOCO_GENESIS_HASH),
+		AssetHubRococo::para_id(),
+	);
+	let wnds_in_reserve_on_ahw_before =
+		<AssetHubWestend as Chain>::account_data_of(sov_ahr_on_ahw.clone()).free;
+	let pens_in_reserve_on_ahw_before = AssetHubWestend::execute_with(|| {
+		type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
+		<ForeignAssets as Inspect<_>>::balance(pens_at_ahw.clone(), &sov_ahr_on_ahw)
+	});
+	let receiver_wnds_before = AssetHubRococo::execute_with(|| {
+		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(
+			wnd_at_rococo_parachains.clone(),
+			&AssetHubRococoReceiver::get(),
+		)
+	});
+	let receiver_pens_before = AssetHubRococo::execute_with(|| {
+		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(
+			pens_at_rococo_parachains.clone(),
+			&AssetHubRococoReceiver::get(),
+		)
+	});
+
+	// transfer assets
+	do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
+		(wnd_at_westend_parachains.clone(), wnds_to_send),
+		(pens_location_on_penpal.try_into().unwrap(), pens_to_send),
+	);
+
+	AssetHubRococo::execute_with(|| {
+		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
+		assert_expected_events!(
+			AssetHubRococo,
+			vec![
+				// issue WNDs on AHR
+				RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => {
+					asset_id: *asset_id == wnd_at_westend_parachains.clone().try_into().unwrap(),
+					owner: *owner == AssetHubRococoReceiver::get(),
+				},
+				// message processed successfully
+				RuntimeEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+			]
+		);
+	});
+
+	// account balances after
+	let sender_wnds_after = PenpalB::execute_with(|| {
+		type ForeignAssets = <PenpalB as PenpalBPallet>::ForeignAssets;
+		<ForeignAssets as Inspect<_>>::balance(
+			wnd_at_westend_parachains.into(),
+			&PenpalBSender::get(),
+		)
+	});
+	let sender_pens_after = PenpalB::execute_with(|| {
+		type Assets = <PenpalB as PenpalBPallet>::Assets;
+		<Assets as Inspect<_>>::balance(pens_id_on_penpal, &PenpalBSender::get())
+	});
+	let wnds_in_reserve_on_ahw_after =
+		<AssetHubWestend as Chain>::account_data_of(sov_ahr_on_ahw.clone()).free;
+	let pens_in_reserve_on_ahw_after = AssetHubWestend::execute_with(|| {
+		type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
+		<ForeignAssets as Inspect<_>>::balance(pens_at_ahw, &sov_ahr_on_ahw)
+	});
+	let receiver_wnds_after = AssetHubRococo::execute_with(|| {
+		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(
+			wnd_at_rococo_parachains.clone(),
+			&AssetHubRococoReceiver::get(),
+		)
+	});
+	let receiver_pens_after = AssetHubRococo::execute_with(|| {
+		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(pens_at_rococo_parachains, &AssetHubRococoReceiver::get())
+	});
+
+	// Sender's balance is reduced
+	assert!(sender_wnds_after < sender_wnds_before);
+	// Receiver's balance is increased
+	assert!(receiver_wnds_after > receiver_wnds_before);
+	// Reserve balance is increased by sent amount (less fess)
+	assert!(wnds_in_reserve_on_ahw_after > wnds_in_reserve_on_ahw_before);
+	assert!(wnds_in_reserve_on_ahw_after <= wnds_in_reserve_on_ahw_before + wnds_to_send);
+
+	// Sender's balance is reduced by sent amount
+	assert_eq!(sender_pens_after, sender_pens_before - pens_to_send);
+	// Reserve balance is increased by sent amount
+	assert_eq!(pens_in_reserve_on_ahw_after, pens_in_reserve_on_ahw_before + pens_to_send);
+	// Receiver's balance is increased by sent amount
+	assert_eq!(receiver_pens_after, receiver_pens_before + pens_to_send);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs
index e62ce684325..c111eb86501 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = BridgeHubWestendExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount);
+	test_chain_can_claim_assets!(
+		AssetHubWestend,
+		RuntimeCall,
+		NetworkId::ByGenesis(WESTEND_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs
index af11f0f7ba7..6c1cdb98e8b 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs
@@ -19,16 +19,28 @@ mod asset_transfers;
 mod claim_assets;
 mod register_bridged_assets;
 mod send_xcm;
-mod teleport;
-
 mod snowbridge;
+mod teleport;
+mod transact;
 
 pub(crate) fn asset_hub_rococo_location() -> Location {
-	Location::new(2, [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())])
+	Location::new(
+		2,
+		[
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
+			Parachain(AssetHubRococo::para_id().into()),
+		],
+	)
 }
 
 pub(crate) fn bridge_hub_rococo_location() -> Location {
-	Location::new(2, [GlobalConsensus(Rococo), Parachain(BridgeHubRococo::para_id().into())])
+	Location::new(
+		2,
+		[
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
+			Parachain(BridgeHubRococo::para_id().into()),
+		],
+	)
 }
 
 // WND and wWND
@@ -36,7 +48,7 @@ pub(crate) fn wnd_at_ah_westend() -> Location {
 	Parent.into()
 }
 pub(crate) fn bridged_wnd_at_ah_rococo() -> Location {
-	Location::new(2, [GlobalConsensus(Westend)])
+	Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))])
 }
 
 // ROC and wROC
@@ -44,7 +56,7 @@ pub(crate) fn roc_at_ah_rococo() -> Location {
 	Parent.into()
 }
 pub(crate) fn bridged_roc_at_ah_westend() -> Location {
-	Location::new(2, [GlobalConsensus(Rococo)])
+	Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))])
 }
 
 // USDT and wUSDT
@@ -55,7 +67,7 @@ pub(crate) fn bridged_usdt_at_ah_rococo() -> Location {
 	Location::new(
 		2,
 		[
-			GlobalConsensus(Westend),
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 			Parachain(AssetHubWestend::para_id().into()),
 			PalletInstance(ASSETS_PALLET_ID),
 			GeneralIndex(USDT_ID.into()),
@@ -74,13 +86,13 @@ pub(crate) fn weth_at_asset_hubs() -> Location {
 	)
 }
 
-pub(crate) fn create_foreign_on_ah_rococo(id: v4::Location, sufficient: bool) {
+pub(crate) fn create_foreign_on_ah_rococo(id: v5::Location, sufficient: bool) {
 	let owner = AssetHubRococo::account_id_of(ALICE);
 	AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]);
 }
 
 pub(crate) fn create_foreign_on_ah_westend(
-	id: v4::Location,
+	id: v5::Location,
 	sufficient: bool,
 	prefund_accounts: Vec<(AccountId, u128)>,
 ) {
@@ -89,74 +101,83 @@ pub(crate) fn create_foreign_on_ah_westend(
 	AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts);
 }
 
-pub(crate) fn foreign_balance_on_ah_rococo(id: v4::Location, who: &AccountId) -> u128 {
+pub(crate) fn foreign_balance_on_ah_rococo(id: v5::Location, who: &AccountId) -> u128 {
 	AssetHubRococo::execute_with(|| {
 		type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
 		<Assets as Inspect<_>>::balance(id, who)
 	})
 }
-pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 {
+pub(crate) fn foreign_balance_on_ah_westend(id: v5::Location, who: &AccountId) -> u128 {
 	AssetHubWestend::execute_with(|| {
 		type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
 		<Assets as Inspect<_>>::balance(id, who)
 	})
 }
 
-// set up pool
-pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v4::Location, is_foreign: bool) {
-	let roc: v4::Location = v4::Parent.into();
-	AssetHubRococo::execute_with(|| {
-		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
-		let owner = AssetHubRococoSender::get();
-		let signed_owner = <AssetHubRococo as Chain>::RuntimeOrigin::signed(owner.clone());
+/// note: $asset needs to be prefunded outside this function
+#[macro_export]
+macro_rules! create_pool_with_native_on {
+	( $chain:ident, $asset:expr, $is_foreign:expr, $asset_owner:expr ) => {
+		emulated_integration_tests_common::impls::paste::paste! {
+			<$chain>::execute_with(|| {
+				type RuntimeEvent = <$chain as Chain>::RuntimeEvent;
+				let owner = $asset_owner;
+				let signed_owner = <$chain as Chain>::RuntimeOrigin::signed(owner.clone());
+				let native_asset: Location = Parent.into();
 
-		if is_foreign {
-			assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::mint(
-				signed_owner.clone(),
-				asset.clone().into(),
-				owner.clone().into(),
-				3_000_000_000_000,
-			));
-		} else {
-			let asset_id = match asset.interior.last() {
-				Some(v4::Junction::GeneralIndex(id)) => *id as u32,
-				_ => unreachable!(),
-			};
-			assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::Assets::mint(
-				signed_owner.clone(),
-				asset_id.into(),
-				owner.clone().into(),
-				3_000_000_000_000,
-			));
+				if $is_foreign {
+					assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint(
+						signed_owner.clone(),
+						$asset.clone().into(),
+						owner.clone().into(),
+						10_000_000_000_000, // For it to have more than enough.
+					));
+				} else {
+					let asset_id = match $asset.interior.last() {
+						Some(GeneralIndex(id)) => *id as u32,
+						_ => unreachable!(),
+					};
+					assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint(
+						signed_owner.clone(),
+						asset_id.into(),
+						owner.clone().into(),
+						10_000_000_000_000, // For it to have more than enough.
+					));
+				}
+
+				assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool(
+					signed_owner.clone(),
+					Box::new(native_asset.clone()),
+					Box::new($asset.clone()),
+				));
+
+				assert_expected_events!(
+					$chain,
+					vec![
+						RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
+					]
+				);
+
+				assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity(
+					signed_owner,
+					Box::new(native_asset),
+					Box::new($asset),
+					1_000_000_000_000,
+					2_000_000_000_000, // $asset is worth half of native_asset
+					0,
+					0,
+					owner.into()
+				));
+
+				assert_expected_events!(
+					$chain,
+					vec![
+						RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
+					]
+				);
+			});
 		}
-		assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::AssetConversion::create_pool(
-			signed_owner.clone(),
-			Box::new(roc.clone()),
-			Box::new(asset.clone()),
-		));
-		assert_expected_events!(
-			AssetHubRococo,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {},
-			]
-		);
-		assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::AssetConversion::add_liquidity(
-			signed_owner.clone(),
-			Box::new(roc),
-			Box::new(asset),
-			1_000_000_000_000,
-			2_000_000_000_000,
-			1,
-			1,
-			owner.into()
-		));
-		assert_expected_events!(
-			AssetHubRococo,
-			vec![
-				RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {},
-			]
-		);
-	});
+	};
 }
 
 pub(crate) fn send_assets_from_asset_hub_westend(
@@ -239,7 +260,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() {
 	BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5);
 	AssetHubRococo::open_bridge(
 		AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()),
-		[GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(),
+		[
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+			Parachain(AssetHubWestend::para_id().into()),
+		]
+		.into(),
 		Some((
 			(roc_at_ah_rococo(), ROC * 1).into(),
 			BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of(
@@ -252,7 +277,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() {
 	BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5);
 	AssetHubWestend::open_bridge(
 		AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()),
-		[GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(),
+		[
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
+			Parachain(AssetHubRococo::para_id().into()),
+		]
+		.into(),
 		Some((
 			(wnd_at_ah_westend(), WND * 1).into(),
 			BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of(
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs
index 7a7ad6da2d5..424f1e55956 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs
@@ -30,7 +30,7 @@ fn register_westend_asset_on_rah_from_wah() {
 	let bridged_asset_at_rah = Location::new(
 		2,
 		[
-			GlobalConsensus(Westend),
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 			Parachain(AssetHubWestend::para_id().into()),
 			PalletInstance(ASSETS_PALLET_ID),
 			GeneralIndex(ASSET_ID.into()),
@@ -57,7 +57,7 @@ fn register_ethereum_asset_on_rah_from_wah() {
 
 fn register_asset_on_rah_from_wah(bridged_asset_at_rah: Location) {
 	let sa_of_wah_on_rah = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus(
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		AssetHubWestend::para_id(),
 	);
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
index ae05e4223b0..787d7dc842c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs
@@ -29,7 +29,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable
 	let xcm = VersionedXcm::from(Xcm(vec![
 		UnpaidExecution { weight_limit, check_origin },
 		ExportMessage {
-			network: RococoId,
+			network: ByGenesis(ROCOCO_GENESIS_HASH),
 			destination: [Parachain(AssetHubRococo::para_id().into())].into(),
 			xcm: remote_xcm,
 		},
@@ -60,15 +60,6 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable
 
 #[test]
 fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
-	// Initially set only default version on all runtimes
-	let newer_xcm_version = xcm::prelude::XCM_VERSION;
-	let older_xcm_version = newer_xcm_version - 1;
-
-	AssetHubRococo::force_default_xcm_version(Some(older_xcm_version));
-	BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version));
-	BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version));
-	AssetHubWestend::force_default_xcm_version(Some(older_xcm_version));
-
 	// prepare data
 	let destination = asset_hub_rococo_location();
 	let native_token = Location::parent();
@@ -82,6 +73,14 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
 	// open bridge
 	open_bridge_between_asset_hub_rococo_and_asset_hub_westend();
 
+	// Initially set only default version on all runtimes
+	let newer_xcm_version = xcm::prelude::XCM_VERSION;
+	let older_xcm_version = newer_xcm_version - 1;
+	AssetHubRococo::force_default_xcm_version(Some(older_xcm_version));
+	BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version));
+	BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version));
+	AssetHubWestend::force_default_xcm_version(Some(older_xcm_version));
+
 	// send XCM from AssetHubWestend - fails - destination version not known
 	assert_err!(
 		send_assets_from_asset_hub_westend(
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs
index f1c27aedf16..ffa60a4f52e 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs
@@ -96,8 +96,10 @@ fn send_token_from_ethereum_to_asset_hub() {
 	// Fund ethereum sovereign on AssetHub
 	AssetHubWestend::fund_accounts(vec![(AssetHubWestendReceiver::get(), INITIAL_FUND)]);
 
+	let ethereum_network_v5: NetworkId = EthereumNetwork::get().into();
+
 	let weth_asset_location: Location =
-		(Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into();
+		(Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into();
 
 	AssetHubWestend::execute_with(|| {
 		type RuntimeOrigin = <AssetHubWestend as Chain>::RuntimeOrigin;
@@ -156,8 +158,9 @@ fn send_token_from_ethereum_to_asset_hub() {
 fn send_weth_asset_from_asset_hub_to_ethereum() {
 	let assethub_location = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id());
 	let assethub_sovereign = BridgeHubWestend::sovereign_account_id_of(assethub_location);
+	let ethereum_network_v5: NetworkId = EthereumNetwork::get().into();
 	let weth_asset_location: Location =
-		(Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into();
+		(Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into();
 
 	BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]);
 
@@ -218,14 +221,14 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
 			)),
 			fun: Fungible(TOKEN_AMOUNT),
 		}];
-		let versioned_assets = VersionedAssets::V4(Assets::from(assets));
+		let versioned_assets = VersionedAssets::from(Assets::from(assets));
 
-		let destination = VersionedLocation::V4(Location::new(
+		let destination = VersionedLocation::from(Location::new(
 			2,
 			[GlobalConsensus(Ethereum { chain_id: CHAIN_ID })],
 		));
 
-		let beneficiary = VersionedLocation::V4(Location::new(
+		let beneficiary = VersionedLocation::from(Location::new(
 			0,
 			[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
 		));
@@ -291,8 +294,10 @@ fn transfer_relay_token() {
 	BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]);
 
 	let asset_id: Location = Location { parents: 1, interior: [].into() };
-	let expected_asset_id: Location =
-		Location { parents: 1, interior: [GlobalConsensus(Westend)].into() };
+	let expected_asset_id: Location = Location {
+		parents: 1,
+		interior: [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))].into(),
+	};
 
 	let expected_token_id = TokenIdOf::convert_location(&expected_asset_id).unwrap();
 
@@ -317,7 +322,7 @@ fn transfer_relay_token() {
 
 		assert_ok!(<BridgeHubWestend as BridgeHubWestendPallet>::EthereumSystem::register_token(
 			RuntimeOrigin::root(),
-			Box::new(VersionedLocation::V4(asset_id.clone())),
+			Box::new(VersionedLocation::from(asset_id.clone())),
 			AssetMetadata {
 				name: "wnd".as_bytes().to_vec().try_into().unwrap(),
 				symbol: "wnd".as_bytes().to_vec().try_into().unwrap(),
@@ -337,14 +342,14 @@ fn transfer_relay_token() {
 		type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
 
 		let assets = vec![Asset { id: AssetId(Location::parent()), fun: Fungible(TOKEN_AMOUNT) }];
-		let versioned_assets = VersionedAssets::V4(Assets::from(assets));
+		let versioned_assets = VersionedAssets::from(Assets::from(assets));
 
-		let destination = VersionedLocation::V4(Location::new(
+		let destination = VersionedLocation::from(Location::new(
 			2,
 			[GlobalConsensus(Ethereum { chain_id: CHAIN_ID })],
 		));
 
-		let beneficiary = VersionedLocation::V4(Location::new(
+		let beneficiary = VersionedLocation::from(Location::new(
 			0,
 			[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
 		));
@@ -462,10 +467,15 @@ fn transfer_ah_token() {
 		],
 	);
 
-	let asset_id_after_reanchored =
-		Location::new(1, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())])
-			.appended_with(asset_id.clone().interior)
-			.unwrap();
+	let asset_id_after_reanchored = Location::new(
+		1,
+		[
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+			Parachain(AssetHubWestend::para_id().into()),
+		],
+	)
+	.appended_with(asset_id.clone().interior)
+	.unwrap();
 
 	let token_id = TokenIdOf::convert_location(&asset_id_after_reanchored).unwrap();
 
@@ -475,7 +485,7 @@ fn transfer_ah_token() {
 
 		assert_ok!(<BridgeHubWestend as BridgeHubWestendPallet>::EthereumSystem::register_token(
 			RuntimeOrigin::root(),
-			Box::new(VersionedLocation::V4(asset_id_in_bh.clone())),
+			Box::new(VersionedLocation::from(asset_id_in_bh.clone())),
 			AssetMetadata {
 				name: "ah_asset".as_bytes().to_vec().try_into().unwrap(),
 				symbol: "ah_asset".as_bytes().to_vec().try_into().unwrap(),
@@ -500,9 +510,9 @@ fn transfer_ah_token() {
 		// Send partial of the token, will fail if send all
 		let assets =
 			vec![Asset { id: AssetId(asset_id.clone()), fun: Fungible(TOKEN_AMOUNT / 10) }];
-		let versioned_assets = VersionedAssets::V4(Assets::from(assets));
+		let versioned_assets = VersionedAssets::from(Assets::from(assets));
 
-		let beneficiary = VersionedLocation::V4(Location::new(
+		let beneficiary = VersionedLocation::from(Location::new(
 			0,
 			[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
 		));
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
new file mode 100644
index 00000000000..db42704dae6
--- /dev/null
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs
@@ -0,0 +1,248 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{
+	create_pool_with_native_on,
+	tests::{snowbridge::CHAIN_ID, *},
+};
+use sp_core::Get;
+use xcm::latest::AssetTransferFilter;
+
+const ETHEREUM_BOB: [u8; 20] = hex_literal::hex!("11b0b11000011b0b11000011b0b11000011b0b11");
+
+/// Bob on Ethereum transacts on PenpalB, paying fees using WETH. XCM has to go through Asset Hub
+/// as the reserve location of WETH. The original origin `Ethereum/Bob` is proxied by Asset Hub.
+///
+/// This particular test is not testing snowbridge, but only Bridge Hub, so the tested XCM flow from
+/// Ethereum starts from Bridge Hub.
+// TODO(https://github.com/paritytech/polkadot-sdk/issues/6243): Once Snowbridge supports Transact, start the flow from Ethereum and test completely e2e.
+fn transfer_and_transact_in_same_xcm(
+	sender: Location,
+	weth: Asset,
+	destination: Location,
+	beneficiary: Location,
+	call: xcm::DoubleEncoded<()>,
+) {
+	let signed_origin = <BridgeHubWestend as Chain>::RuntimeOrigin::root();
+	let context: InteriorLocation = [
+		GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
+		Parachain(<BridgeHubWestend as Para>::ParachainInfo::get().into()),
+	]
+	.into();
+	let asset_hub_location = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id());
+
+	// TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get local fees, for now use hardcoded value.
+	let ah_fees_amount = 90_000_000_000u128; // current exact value 79_948_099_299
+	let fees_for_ah: Asset = (weth.id.clone(), ah_fees_amount).into();
+
+	// xcm to be executed at dest
+	let xcm_on_dest = Xcm(vec![
+		Transact { origin_kind: OriginKind::Xcm, call },
+		ExpectTransactStatus(MaybeErrorCode::Success),
+		// since this is the last hop, we don't need to further use any assets previously
+		// reserved for fees (there are no further hops to cover transport fees for); we
+		// RefundSurplus to get back any unspent fees
+		RefundSurplus,
+		DepositAsset { assets: Wild(All), beneficiary },
+	]);
+	let destination = destination.reanchored(&asset_hub_location, &context).unwrap();
+	let xcm_to_ah = Xcm::<()>(vec![
+		UnpaidExecution { check_origin: None, weight_limit: Unlimited },
+		DescendOrigin([PalletInstance(80)].into()), // snowbridge pallet
+		UniversalOrigin(GlobalConsensus(Ethereum { chain_id: CHAIN_ID })),
+		ReserveAssetDeposited(weth.clone().into()),
+		AliasOrigin(sender),
+		PayFees { asset: fees_for_ah },
+		InitiateTransfer {
+			destination,
+			// on the last hop we can just put everything in fees and `RefundSurplus` to get any
+			// unused back
+			remote_fees: Some(AssetTransferFilter::ReserveDeposit(Wild(All))),
+			preserve_origin: true,
+			assets: vec![],
+			remote_xcm: xcm_on_dest,
+		},
+	]);
+	<BridgeHubWestend as BridgeHubWestendPallet>::PolkadotXcm::send(
+		signed_origin,
+		bx!(asset_hub_location.into()),
+		bx!(xcm::VersionedXcm::from(xcm_to_ah.into())),
+	)
+	.unwrap();
+}
+
+/// Bob on Ethereum transacts on PenpalB, paying fees using WETH. XCM has to go through Asset Hub
+/// as the reserve location of WETH. The original origin `Ethereum/Bob` is proxied by Asset Hub.
+///
+/// This particular test is not testing snowbridge, but only Bridge Hub, so the tested XCM flow from
+/// Ethereum starts from Bridge Hub.
+// TODO(https://github.com/paritytech/polkadot-sdk/issues/6243): Once Snowbridge supports Transact, start the flow from Ethereum and test completely e2e.
+#[test]
+fn transact_from_ethereum_to_penpalb_through_asset_hub() {
+	// Snowbridge doesn't support transact yet, we are emulating it by sending one from Bridge Hub
+	// as if it comes from Snowbridge.
+	let destination = BridgeHubWestend::sibling_location_of(PenpalB::para_id());
+	let sender = Location::new(
+		2,
+		[
+			GlobalConsensus(Ethereum { chain_id: CHAIN_ID }),
+			AccountKey20 { network: None, key: ETHEREUM_BOB },
+		],
+	);
+
+	let bridged_weth = weth_at_asset_hubs();
+	AssetHubWestend::force_create_foreign_asset(
+		bridged_weth.clone(),
+		PenpalAssetOwner::get(),
+		true,
+		ASSET_MIN_BALANCE,
+		vec![],
+	);
+	PenpalB::force_create_foreign_asset(
+		bridged_weth.clone(),
+		PenpalAssetOwner::get(),
+		true,
+		ASSET_MIN_BALANCE,
+		vec![],
+	);
+	// Configure source Penpal chain to trust local AH as reserve of bridged WETH
+	PenpalB::execute_with(|| {
+		assert_ok!(<PenpalB as Chain>::System::set_storage(
+			<PenpalB as Chain>::RuntimeOrigin::root(),
+			vec![(
+				PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(),
+				bridged_weth.encode(),
+			)],
+		));
+	});
+
+	let fee_amount_to_send: parachains_common::Balance = ASSET_HUB_WESTEND_ED * 10000;
+	let sender_chain_as_seen_by_asset_hub =
+		Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]);
+
+	let sov_of_sender_on_asset_hub = AssetHubWestend::execute_with(|| {
+		AssetHubWestend::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub)
+	});
+	let receiver_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalB::para_id());
+	let sov_of_receiver_on_asset_hub = AssetHubWestend::execute_with(|| {
+		AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_asset_hub)
+	});
+	// Create SAs of sender and receiver on AHW with ED.
+	AssetHubWestend::fund_accounts(vec![
+		(sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED),
+		(sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED),
+	]);
+
+	// We create a pool between WND and WETH in AssetHub to support paying for fees with WETH.
+	let ahw_owner = AssetHubWestendSender::get();
+	create_pool_with_native_on!(AssetHubWestend, bridged_weth.clone(), true, ahw_owner);
+	// We also need a pool between WND and WETH on PenpalB to support paying for fees with WETH.
+	create_pool_with_native_on!(PenpalB, bridged_weth.clone(), true, PenpalAssetOwner::get());
+
+	// Init values for Parachain Destination
+	let receiver = PenpalBReceiver::get();
+
+	// Query initial balances
+	let receiver_assets_before = PenpalB::execute_with(|| {
+		type Assets = <PenpalB as PenpalBPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(bridged_weth.clone(), &receiver)
+	});
+
+	// Now register a new asset on PenpalB from Ethereum/Bob account while paying fees using WETH
+	// (going through Asset Hub)
+	let weth_to_send: Asset = (bridged_weth.clone(), fee_amount_to_send).into();
+	// Silly example of a Transact: Bob creates his own foreign assset on PenpalB based on his
+	// Ethereum address
+	let foreign_asset_at_penpal_b = Location::new(
+		2,
+		[
+			GlobalConsensus(Ethereum { chain_id: CHAIN_ID }),
+			AccountKey20 { network: None, key: ETHEREUM_BOB },
+		],
+	);
+	// Encoded `create_asset` call to be executed in PenpalB
+	let call = PenpalB::create_foreign_asset_call(
+		foreign_asset_at_penpal_b.clone(),
+		ASSET_MIN_BALANCE,
+		receiver.clone(),
+	);
+	BridgeHubWestend::execute_with(|| {
+		// initiate transaction
+		transfer_and_transact_in_same_xcm(
+			sender.clone(),
+			weth_to_send,
+			destination,
+			receiver.clone().into(),
+			call,
+		);
+	});
+	AssetHubWestend::execute_with(|| {
+		let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of(
+			AssetHubWestend::sibling_location_of(PenpalB::para_id()),
+		);
+		asset_hub_hop_assertions(sov_penpal_b_on_ah);
+	});
+	PenpalB::execute_with(|| {
+		let expected_creator = PenpalB::sovereign_account_id_of(sender);
+		penpal_b_assertions(foreign_asset_at_penpal_b, expected_creator, receiver.clone());
+	});
+
+	// Query final balances
+	let receiver_assets_after = PenpalB::execute_with(|| {
+		type Assets = <PenpalB as PenpalBPallet>::ForeignAssets;
+		<Assets as Inspect<_>>::balance(bridged_weth, &receiver)
+	});
+	// Receiver's balance is increased
+	assert!(receiver_assets_after > receiver_assets_before);
+}
+
+fn asset_hub_hop_assertions(receiver_sa: AccountId) {
+	type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
+	assert_expected_events!(
+		AssetHubWestend,
+		vec![
+			// Deposited to receiver parachain SA
+			RuntimeEvent::ForeignAssets(
+				pallet_assets::Event::Deposited { who, .. }
+			) => {
+				who: *who == receiver_sa,
+			},
+			RuntimeEvent::MessageQueue(
+				pallet_message_queue::Event::Processed { success: true, .. }
+			) => {},
+		]
+	);
+}
+
+fn penpal_b_assertions(
+	expected_asset: Location,
+	expected_creator: AccountId,
+	expected_owner: AccountId,
+) {
+	type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
+	PenpalB::assert_xcmp_queue_success(None);
+	assert_expected_events!(
+		PenpalB,
+		vec![
+			RuntimeEvent::ForeignAssets(
+				pallet_assets::Event::Created { asset_id, creator, owner }
+			) => {
+				asset_id: *asset_id == expected_asset,
+				creator: *creator == expected_creator,
+				owner: *owner == expected_owner,
+			},
+		]
+	);
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
index f97599bda7f..80b82e0c446 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs
@@ -36,7 +36,6 @@ fn fellows_whitelist_call() {
 				UnpaidExecution { weight_limit: Unlimited, check_origin: None },
 				Transact {
 					origin_kind: OriginKind::Xcm,
-					require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000),
 					call: WestendCall::Whitelist(
 						pallet_whitelist::Call::<WestendRuntime>::whitelist_call { call_hash }
 					)
diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs
index 943f8965540..8418e3da3bb 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs
@@ -64,11 +64,12 @@ fn fellowship_treasury_spend() {
 		let teleport_call = RuntimeCall::Utility(pallet_utility::Call::<Runtime>::dispatch_as {
 			as_origin: bx!(WestendOriginCaller::system(RawOrigin::Signed(treasury_account))),
 			call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::<Runtime>::teleport_assets {
-				dest: bx!(VersionedLocation::V4(asset_hub_location.clone())),
-				beneficiary: bx!(VersionedLocation::V4(treasury_location)),
-				assets: bx!(VersionedAssets::V4(
-					Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into()
-				)),
+				dest: bx!(VersionedLocation::from(asset_hub_location.clone())),
+				beneficiary: bx!(VersionedLocation::from(treasury_location)),
+				assets: bx!(VersionedAssets::from(Assets::from(Asset {
+					id: native_asset.clone().into(),
+					fun: treasury_balance.into()
+				}))),
 				fee_asset_item: 0,
 			})),
 		});
@@ -101,12 +102,12 @@ fn fellowship_treasury_spend() {
 		let native_asset = Location::parent();
 
 		let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::<Runtime>::spend {
-			asset_kind: bx!(VersionedLocatableAsset::V4 {
-				location: asset_hub_location.clone(),
-				asset_id: native_asset.into(),
-			}),
+			asset_kind: bx!(VersionedLocatableAsset::from((
+				asset_hub_location.clone(),
+				native_asset.into()
+			))),
 			amount: fellowship_treasury_balance,
-			beneficiary: bx!(VersionedLocation::V4(fellowship_treasury_location)),
+			beneficiary: bx!(VersionedLocation::from(fellowship_treasury_location)),
 			valid_from: None,
 		});
 
@@ -179,12 +180,12 @@ fn fellowship_treasury_spend() {
 
 		let fellowship_treasury_spend_call =
 			RuntimeCall::FellowshipTreasury(pallet_treasury::Call::<Runtime, Instance1>::spend {
-				asset_kind: bx!(VersionedLocatableAsset::V4 {
-					location: asset_hub_location,
-					asset_id: native_asset.into(),
-				}),
+				asset_kind: bx!(VersionedLocatableAsset::from((
+					asset_hub_location,
+					native_asset.into()
+				))),
 				amount: fellowship_spend_balance,
-				beneficiary: bx!(VersionedLocation::V4(alice_location)),
+				beneficiary: bx!(VersionedLocation::from(alice_location)),
 				valid_from: None,
 			});
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
index 055bd50d829..d3fec423036 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
@@ -20,7 +20,7 @@ mod imports {
 	pub use frame_support::assert_ok;
 
 	// Polkadot
-	pub use xcm::prelude::*;
+	pub use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*};
 
 	// Cumulus
 	pub use emulated_integration_tests_common::xcm_emulator::{
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs
index e37b915174d..bdab86f5cbf 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = CoretimeRococoExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(CoretimeRococo, RuntimeCall, NetworkId::Rococo, assets, amount);
+	test_chain_can_claim_assets!(
+		CoretimeRococo,
+		RuntimeCall,
+		NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
index ac844e0f328..4fb619aba3d 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
@@ -20,7 +20,7 @@ mod imports {
 	pub use frame_support::assert_ok;
 
 	// Polkadot
-	pub use xcm::prelude::*;
+	pub use xcm::{latest::WESTEND_GENESIS_HASH, prelude::*};
 
 	// Cumulus
 	pub use emulated_integration_tests_common::xcm_emulator::{
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs
index c8d85369844..3cabc3f8ac5 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = CoretimeWestendExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(CoretimeWestend, RuntimeCall, NetworkId::Westend, assets, amount);
+	test_chain_can_claim_assets!(
+		CoretimeWestend,
+		RuntimeCall,
+		NetworkId::ByGenesis(WESTEND_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs
index 06b0b6ba600..a95396d5070 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs
@@ -19,7 +19,7 @@ mod imports {
 	pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect};
 
 	// Polkadot
-	pub use xcm::prelude::*;
+	pub use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*};
 
 	// Cumulus
 	pub use asset_test_utils::xcm_helpers;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs
index 793200e1d06..6795b1e7f39 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = PeopleRococoExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(PeopleRococo, RuntimeCall, NetworkId::Rococo, assets, amount);
+	test_chain_can_claim_assets!(
+		PeopleRococo,
+		RuntimeCall,
+		NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs
index 418cfea07dd..59d87e1ea3f 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs
@@ -19,7 +19,7 @@ mod imports {
 	pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect};
 
 	// Polkadot
-	pub use xcm::prelude::*;
+	pub use xcm::{latest::WESTEND_GENESIS_HASH, prelude::*};
 
 	// Cumulus
 	pub use asset_test_utils::xcm_helpers;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs
index 42ccc459286..055c713abfd 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs
@@ -25,5 +25,11 @@ fn assets_can_be_claimed() {
 	let amount = PeopleWestendExistentialDeposit::get();
 	let assets: Assets = (Parent, amount).into();
 
-	test_chain_can_claim_assets!(PeopleWestend, RuntimeCall, NetworkId::Westend, assets, amount);
+	test_chain_can_claim_assets!(
+		PeopleWestend,
+		RuntimeCall,
+		NetworkId::ByGenesis(WESTEND_GENESIS_HASH),
+		assets,
+		amount
+	);
 }
diff --git a/cumulus/parachains/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs
index 729494cbd25..2cf32c891fc 100644
--- a/cumulus/parachains/pallets/ping/src/lib.rs
+++ b/cumulus/parachains/pallets/ping/src/lib.rs
@@ -108,7 +108,6 @@ pub mod pallet {
 					(Parent, Junction::Parachain(para.into())).into(),
 					Xcm(vec![Transact {
 						origin_kind: OriginKind::Native,
-						require_weight_at_most: Weight::from_parts(1_000, 1_000),
 						call: <T as Config>::RuntimeCall::from(Call::<T>::ping {
 							seq,
 							payload: payload.clone().to_vec(),
@@ -209,7 +208,6 @@ pub mod pallet {
 				(Parent, Junction::Parachain(para.into())).into(),
 				Xcm(vec![Transact {
 					origin_kind: OriginKind::Native,
-					require_weight_at_most: Weight::from_parts(1_000, 1_000),
 					call: <T as Config>::RuntimeCall::from(Call::<T>::pong {
 						seq,
 						payload: payload.clone(),
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
index 474434448bb..2f9d83bd9d0 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
@@ -330,11 +330,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
 	Assets,
 	ForeignAssets,
 	LocalFromLeft<
-		AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, xcm::v4::Location>,
+		AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, xcm::v5::Location>,
 		AssetIdForTrustBackedAssets,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>,
-	xcm::v4::Location,
+	xcm::v5::Location,
 	AccountId,
 >;
 
@@ -342,21 +342,21 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
 pub type NativeAndAssets = fungible::UnionOf<
 	Balances,
 	LocalAndForeignAssets,
-	TargetFromLeft<TokenLocation, xcm::v4::Location>,
-	xcm::v4::Location,
+	TargetFromLeft<TokenLocation, xcm::v5::Location>,
+	xcm::v5::Location,
 	AccountId,
 >;
 
 pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter<
 	AssetConversionPalletId,
-	(xcm::v4::Location, xcm::v4::Location),
+	(xcm::v5::Location, xcm::v5::Location),
 >;
 
 impl pallet_asset_conversion::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Balance = Balance;
 	type HigherPrecisionBalance = sp_core::U256;
-	type AssetKind = xcm::v4::Location;
+	type AssetKind = xcm::v5::Location;
 	type Assets = NativeAndAssets;
 	type PoolId = (Self::AssetKind, Self::AssetKind);
 	type PoolLocator = pallet_asset_conversion::WithFirstAsset<
@@ -381,7 +381,7 @@ impl pallet_asset_conversion::Config for Runtime {
 		TokenLocation,
 		parachain_info::Pallet<Runtime>,
 		xcm_config::TrustBackedAssetsPalletIndex,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>;
 }
 
@@ -415,18 +415,18 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2;
 impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Balance = Balance;
-	type AssetId = xcm::v4::Location;
-	type AssetIdParameter = xcm::v4::Location;
+	type AssetId = xcm::v5::Location;
+	type AssetIdParameter = xcm::v5::Location;
 	type Currency = Balances;
 	type CreateOrigin = ForeignCreators<
 		(
-			FromSiblingParachain<parachain_info::Pallet<Runtime>, xcm::v4::Location>,
-			FromNetwork<xcm_config::UniversalLocation, EthereumNetwork, xcm::v4::Location>,
+			FromSiblingParachain<parachain_info::Pallet<Runtime>, xcm::v5::Location>,
+			FromNetwork<xcm_config::UniversalLocation, EthereumNetwork, xcm::v5::Location>,
 			xcm_config::bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend,
 		),
 		LocationToAccountId,
 		AccountId,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>;
 	type ForceOrigin = AssetsForceOrigin;
 	type AssetDeposit = ForeignAssetsAssetDeposit;
@@ -813,7 +813,7 @@ parameter_types! {
 
 impl pallet_asset_conversion_tx_payment::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
-	type AssetId = xcm::v4::Location;
+	type AssetId = xcm::v5::Location;
 	type OnChargeAssetTransaction = SwapAssetAdapter<
 		TokenLocation,
 		NativeAndAssets,
@@ -1308,16 +1308,16 @@ impl_runtime_apis! {
 	impl pallet_asset_conversion::AssetConversionApi<
 		Block,
 		Balance,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	> for Runtime
 	{
-		fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
+		fn quote_price_exact_tokens_for_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
 			AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee)
 		}
-		fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
+		fn quote_price_tokens_for_exact_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
 			AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee)
 		}
-		fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> {
+		fn get_reserves(asset1: xcm::v5::Location, asset2: xcm::v5::Location) -> Option<(Balance, Balance)> {
 			AssetConversion::get_reserves(asset1, asset2).ok()
 		}
 	}
@@ -1414,7 +1414,7 @@ impl_runtime_apis! {
 			// We also accept all assets in a pool with the native token.
 			let assets_in_pool_with_native = assets_common::get_assets_in_pool_with::<
 				Runtime,
-				xcm::v4::Location
+				xcm::v5::Location
 			>(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter();
 			acceptable_assets.extend(assets_in_pool_with_native);
 			PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets)
@@ -1431,7 +1431,7 @@ impl_runtime_apis! {
 				Ok(asset_id) => {
 					let assets_in_pool_with_this_asset: Vec<_> = assets_common::get_assets_in_pool_with::<
 						Runtime,
-						xcm::v4::Location
+						xcm::v5::Location
 					>(&asset_id.0).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?;
 					if assets_in_pool_with_this_asset
 						.into_iter()
@@ -1834,7 +1834,12 @@ impl_runtime_apis! {
 				}
 
 				fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
-					Err(BenchmarkError::Skip)
+					// Any location can alias to an internal location.
+					// Here parachain 1001 aliases to an internal account.
+					Ok((
+						Location::new(1, [Parachain(1001)]),
+						Location::new(1, [Parachain(1001), AccountId32 { id: [111u8; 32], network: None }]),
+					))
 				}
 			}
 
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
index 8c52ecd9f1b..bf374fc415c 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
@@ -22,7 +22,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -81,11 +84,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -132,12 +131,35 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -150,6 +172,9 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 	fn clear_error() -> Weight {
 		XcmGeneric::<Runtime>::clear_error()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 	fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight {
 		XcmGeneric::<Runtime>::claim_asset()
 	}
@@ -223,8 +248,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 		XcmGeneric::<Runtime>::clear_topic()
 	}
 	fn alias_origin(_: &Location) -> Weight {
-		// XCM Executor does not currently support alias origin operations
-		Weight::MAX
+		XcmGeneric::<Runtime>::alias_origin()
 	}
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 7478ba8893c..a2169e2ea04 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 34_364_000 picoseconds.
-		Weight::from_parts(35_040_000, 3593)
+		// Minimum execution time: 33_878_000 picoseconds.
+		Weight::from_parts(34_766_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 42_755_000 picoseconds.
-		Weight::from_parts(43_650_000, 6196)
+		// Minimum execution time: 42_776_000 picoseconds.
+		Weight::from_parts(43_643_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -90,8 +90,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `8799`
-		// Minimum execution time: 103_037_000 picoseconds.
-		Weight::from_parts(105_732_000, 8799)
+		// Minimum execution time: 104_654_000 picoseconds.
+		Weight::from_parts(106_518_000, 8799)
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
@@ -99,8 +99,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_095_000 picoseconds.
-		Weight::from_parts(1_220_000, 0)
+		// Minimum execution time: 1_183_000 picoseconds.
+		Weight::from_parts(1_309_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -122,8 +122,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 108_117_000 picoseconds.
-		Weight::from_parts(110_416_000, 6196)
+		// Minimum execution time: 112_272_000 picoseconds.
+		Weight::from_parts(114_853_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -131,8 +131,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_907_000 picoseconds.
-		Weight::from_parts(3_050_000, 0)
+		// Minimum execution time: 2_769_000 picoseconds.
+		Weight::from_parts(2_916_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -140,8 +140,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 24_965_000 picoseconds.
-		Weight::from_parts(25_687_000, 3593)
+		// Minimum execution time: 26_145_000 picoseconds.
+		Weight::from_parts(26_589_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -165,8 +165,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `6196`
-		// Minimum execution time: 83_312_000 picoseconds.
-		Weight::from_parts(85_463_000, 6196)
+		// Minimum execution time: 85_446_000 picoseconds.
+		Weight::from_parts(88_146_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -190,9 +190,34 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 49_874_000 picoseconds.
-		Weight::from_parts(51_165_000, 3610)
+		// Minimum execution time: 55_060_000 picoseconds.
+		Weight::from_parts(56_120_000, 3610)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
+	// Storage: `System::Account` (r:2 w:2)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `6196`
+		// Minimum execution time: 90_870_000 picoseconds.
+		Weight::from_parts(93_455_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(9))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index f6a883c03e9..ef08b432e5c 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -68,8 +68,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 99_552_000 picoseconds.
-		Weight::from_parts(101_720_000, 6196)
+		// Minimum execution time: 103_506_000 picoseconds.
+		Weight::from_parts(106_039_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -77,8 +77,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 659_000 picoseconds.
-		Weight::from_parts(706_000, 0)
+		// Minimum execution time: 668_000 picoseconds.
+		Weight::from_parts(743_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 5_803_000 picoseconds.
+		Weight::from_parts(5_983_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 644_000 picoseconds.
+		Weight::from_parts(684_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -86,58 +100,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3568`
-		// Minimum execution time: 9_665_000 picoseconds.
-		Weight::from_parts(9_878_000, 3568)
+		// Minimum execution time: 9_957_000 picoseconds.
+		Weight::from_parts(10_163_000, 3568)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_959_000 picoseconds.
-		Weight::from_parts(7_111_000, 0)
+		// Minimum execution time: 6_663_000 picoseconds.
+		Weight::from_parts(7_134_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_682_000 picoseconds.
-		Weight::from_parts(2_799_000, 0)
+		// Minimum execution time: 3_067_000 picoseconds.
+		Weight::from_parts(3_175_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 656_000 picoseconds.
-		Weight::from_parts(683_000, 0)
+		// Minimum execution time: 650_000 picoseconds.
+		Weight::from_parts(691_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 687_000 picoseconds.
-		Weight::from_parts(719_000, 0)
+		// Minimum execution time: 669_000 picoseconds.
+		Weight::from_parts(703_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 588_000 picoseconds.
-		Weight::from_parts(653_000, 0)
+		// Minimum execution time: 649_000 picoseconds.
+		Weight::from_parts(691_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
 		// Minimum execution time: 690_000 picoseconds.
-		Weight::from_parts(714_000, 0)
+		Weight::from_parts(735_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 671_000 picoseconds.
-		Weight::from_parts(710_000, 0)
+		// Minimum execution time: 681_000 picoseconds.
+		Weight::from_parts(735_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -159,8 +173,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_374_000 picoseconds.
-		Weight::from_parts(68_899_000, 6196)
+		// Minimum execution time: 68_877_000 picoseconds.
+		Weight::from_parts(69_996_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -170,8 +184,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `160`
 		//  Estimated: `3625`
-		// Minimum execution time: 12_896_000 picoseconds.
-		Weight::from_parts(13_191_000, 3625)
+		// Minimum execution time: 13_276_000 picoseconds.
+		Weight::from_parts(13_586_000, 3625)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -179,8 +193,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 634_000 picoseconds.
-		Weight::from_parts(677_000, 0)
+		// Minimum execution time: 659_000 picoseconds.
+		Weight::from_parts(721_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -200,8 +214,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 28_197_000 picoseconds.
-		Weight::from_parts(28_752_000, 3610)
+		// Minimum execution time: 28_656_000 picoseconds.
+		Weight::from_parts(29_175_000, 3610)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -211,44 +225,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_678_000 picoseconds.
-		Weight::from_parts(2_803_000, 0)
+		// Minimum execution time: 2_608_000 picoseconds.
+		Weight::from_parts(2_876_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 22_806_000 picoseconds.
-		Weight::from_parts(23_217_000, 0)
+		// Minimum execution time: 24_035_000 picoseconds.
+		Weight::from_parts(24_315_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_221_000 picoseconds.
-		Weight::from_parts(6_347_000, 0)
+		// Minimum execution time: 6_558_000 picoseconds.
+		Weight::from_parts(6_711_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 653_000 picoseconds.
-		Weight::from_parts(676_000, 0)
+		// Minimum execution time: 645_000 picoseconds.
+		Weight::from_parts(700_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 621_000 picoseconds.
-		Weight::from_parts(678_000, 0)
+		// Minimum execution time: 653_000 picoseconds.
+		Weight::from_parts(696_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 770_000 picoseconds.
-		Weight::from_parts(829_000, 0)
+		// Minimum execution time: 787_000 picoseconds.
+		Weight::from_parts(866_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -270,8 +284,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 71_654_000 picoseconds.
-		Weight::from_parts(73_329_000, 6196)
+		// Minimum execution time: 75_093_000 picoseconds.
+		Weight::from_parts(76_165_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -279,8 +293,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_999_000 picoseconds.
-		Weight::from_parts(4_179_000, 0)
+		// Minimum execution time: 4_304_000 picoseconds.
+		Weight::from_parts(4_577_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -302,8 +316,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 66_722_000 picoseconds.
-		Weight::from_parts(68_812_000, 6196)
+		// Minimum execution time: 68_809_000 picoseconds.
+		Weight::from_parts(70_037_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -311,22 +325,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 718_000 picoseconds.
-		Weight::from_parts(745_000, 0)
+		// Minimum execution time: 715_000 picoseconds.
+		Weight::from_parts(766_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 623_000 picoseconds.
-		Weight::from_parts(682_000, 0)
+		// Minimum execution time: 639_000 picoseconds.
+		Weight::from_parts(688_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 664_000 picoseconds.
-		Weight::from_parts(696_000, 0)
+		// Minimum execution time: 638_000 picoseconds.
+		Weight::from_parts(712_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -334,22 +348,29 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `1489`
-		// Minimum execution time: 2_495_000 picoseconds.
-		Weight::from_parts(2_604_000, 1489)
+		// Minimum execution time: 2_521_000 picoseconds.
+		Weight::from_parts(2_715_000, 1489)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 645_000 picoseconds.
-		Weight::from_parts(673_000, 0)
+		// Minimum execution time: 619_000 picoseconds.
+		Weight::from_parts(692_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 643_000 picoseconds.
-		Weight::from_parts(701_000, 0)
+		// Minimum execution time: 665_000 picoseconds.
+		Weight::from_parts(716_000, 0)
+	}
+	pub fn alias_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 668_000 picoseconds.
+		Weight::from_parts(726_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs
index 56310959aa8..66743fa3a07 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs
@@ -28,7 +28,7 @@ use frame_support::{
 	parameter_types,
 	traits::{
 		tokens::imbalance::{ResolveAssetTo, ResolveTo},
-		ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess,
+		ConstU32, Contains, Equals, Everything, PalletInfoAccess,
 	},
 };
 use frame_system::EnsureRoot;
@@ -47,26 +47,27 @@ use sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto};
 use testnet_parachains_constants::rococo::snowbridge::{
 	EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX,
 };
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
 use xcm_builder::{
-	AccountId32Aliases, 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,
+	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 TokenLocation: Location = Location::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Rococo;
+	pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation =
 		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
@@ -175,7 +176,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte
 		StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
 	),
 	Balance,
-	xcm::v4::Location,
+	xcm::v5::Location,
 >;
 
 /// Means for transacting foreign assets from different global consensus.
@@ -335,14 +336,14 @@ pub type PoolAssetsExchanger = SingleAssetExchangeAdapter<
 	crate::AssetConversion,
 	crate::NativeAndAssets,
 	(
-		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v4::Location>,
+		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v5::Location>,
 		ForeignAssetsConvertedConcreteId,
 		// `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here.
 		MatchedConvertedConcreteId<
-			xcm::v4::Location,
+			xcm::v5::Location,
 			Balance,
 			Equals<ParentLocation>,
-			WithLatestLocationConverter<xcm::v4::Location>,
+			WithLatestLocationConverter<xcm::v5::Location>,
 			TryConvertInto,
 		>,
 	),
@@ -389,7 +390,7 @@ impl xcm_executor::Config for XcmConfig {
 				TrustBackedAssetsAsLocation<
 					TrustBackedAssetsPalletLocation,
 					Balance,
-					xcm::v4::Location,
+					xcm::v5::Location,
 				>,
 				ForeignAssetsConvertedConcreteId,
 			),
@@ -440,7 +441,8 @@ impl xcm_executor::Config for XcmConfig {
 		(bridging::to_westend::UniversalAliases, bridging::to_ethereum::UniversalAliases);
 	type CallDispatcher = RuntimeCall;
 	type SafeCallFilter = Everything;
-	type Aliasers = Nothing;
+	// We allow any origin to alias into a child sub-location (equivalent to DescendOrigin).
+	type Aliasers = AliasChildLocation;
 	type TransactionalProcessor = FrameTransactionalProcessor;
 	type HrmpNewChannelOpenRequestHandler = ();
 	type HrmpChannelAcceptedHandler = ();
@@ -515,9 +517,9 @@ impl cumulus_pallet_xcm::Config for Runtime {
 /// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
 pub struct XcmBenchmarkHelper;
 #[cfg(feature = "runtime-benchmarks")]
-impl pallet_assets::BenchmarkHelper<xcm::v4::Location> for XcmBenchmarkHelper {
-	fn create_asset_id_parameter(id: u32) -> xcm::v4::Location {
-		xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)])
+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)])
 	}
 }
 
@@ -581,7 +583,7 @@ pub mod bridging {
 				]
 			);
 
-			pub const WestendNetwork: NetworkId = NetworkId::Westend;
+			pub const WestendNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
 			pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 };
 			pub WestendEcosystem: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]);
 			pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]);
@@ -652,7 +654,7 @@ pub mod bridging {
 			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
 			pub BridgeTable: alloc::vec::Vec<NetworkExportTableItem> = alloc::vec![
 				NetworkExportTableItem::new(
-					EthereumNetwork::get(),
+					EthereumNetwork::get().into(),
 					Some(alloc::vec![Junctions::Here]),
 					SiblingBridgeHub::get(),
 					Some((
@@ -665,7 +667,7 @@ pub mod bridging {
 			/// Universal aliases
 			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
 				alloc::vec![
-					(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())),
+					(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())),
 				]
 			);
 		}
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
index 81432313532..5da8b45417a 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
@@ -1078,6 +1078,7 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works(
 mod asset_hub_rococo_tests {
 	use super::*;
 	use asset_hub_rococo_runtime::PolkadotXcm;
+	use xcm::latest::WESTEND_GENESIS_HASH;
 	use xcm_executor::traits::ConvertLocation;
 
 	fn bridging_to_asset_hub_westend() -> TestBridgingConfig {
@@ -1108,8 +1109,10 @@ mod asset_hub_rococo_tests {
 		let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT);
 		let staking_pot = StakingPot::get();
 
-		let foreign_asset_id_location =
-			Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]);
+		let foreign_asset_id_location = Location::new(
+			2,
+			[Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))],
+		);
 		let foreign_asset_id_minimum_balance = 1_000_000_000;
 		// sovereign account as foreign asset owner (can be whoever for this scenario)
 		let foreign_asset_owner =
@@ -1143,7 +1146,7 @@ mod asset_hub_rococo_tests {
 			},
 			(
 				[PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(),
-				GlobalConsensus(Westend),
+				GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 				[Parachain(1000)].into()
 			),
 			|| {
@@ -1182,8 +1185,10 @@ mod asset_hub_rococo_tests {
 		let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT);
 		let staking_pot = StakingPot::get();
 
-		let foreign_asset_id_location =
-			Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]);
+		let foreign_asset_id_location = Location::new(
+			2,
+			[Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))],
+		);
 		let foreign_asset_id_minimum_balance = 1_000_000_000;
 		// sovereign account as foreign asset owner (can be whoever for this scenario)
 		let foreign_asset_owner =
@@ -1210,7 +1215,7 @@ mod asset_hub_rococo_tests {
 			bridging_to_asset_hub_westend,
 			(
 				[PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(),
-				GlobalConsensus(Westend),
+				GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 				[Parachain(1000)].into()
 			),
 			|| {
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
index 7261680677d..63175222cc2 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
@@ -332,11 +332,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
 	Assets,
 	ForeignAssets,
 	LocalFromLeft<
-		AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, xcm::v4::Location>,
+		AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation, xcm::v5::Location>,
 		AssetIdForTrustBackedAssets,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>,
-	xcm::v4::Location,
+	xcm::v5::Location,
 	AccountId,
 >;
 
@@ -344,21 +344,21 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
 pub type NativeAndAssets = fungible::UnionOf<
 	Balances,
 	LocalAndForeignAssets,
-	TargetFromLeft<WestendLocation, xcm::v4::Location>,
-	xcm::v4::Location,
+	TargetFromLeft<WestendLocation, xcm::v5::Location>,
+	xcm::v5::Location,
 	AccountId,
 >;
 
 pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter<
 	AssetConversionPalletId,
-	(xcm::v4::Location, xcm::v4::Location),
+	(xcm::v5::Location, xcm::v5::Location),
 >;
 
 impl pallet_asset_conversion::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Balance = Balance;
 	type HigherPrecisionBalance = sp_core::U256;
-	type AssetKind = xcm::v4::Location;
+	type AssetKind = xcm::v5::Location;
 	type Assets = NativeAndAssets;
 	type PoolId = (Self::AssetKind, Self::AssetKind);
 	type PoolLocator = pallet_asset_conversion::WithFirstAsset<
@@ -383,7 +383,7 @@ impl pallet_asset_conversion::Config for Runtime {
 		WestendLocation,
 		parachain_info::Pallet<Runtime>,
 		xcm_config::TrustBackedAssetsPalletIndex,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>;
 }
 
@@ -417,18 +417,18 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2;
 impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Balance = Balance;
-	type AssetId = xcm::v4::Location;
-	type AssetIdParameter = xcm::v4::Location;
+	type AssetId = xcm::v5::Location;
+	type AssetIdParameter = xcm::v5::Location;
 	type Currency = Balances;
 	type CreateOrigin = ForeignCreators<
 		(
-			FromSiblingParachain<parachain_info::Pallet<Runtime>, xcm::v4::Location>,
-			FromNetwork<xcm_config::UniversalLocation, EthereumNetwork, xcm::v4::Location>,
+			FromSiblingParachain<parachain_info::Pallet<Runtime>, xcm::v5::Location>,
+			FromNetwork<xcm_config::UniversalLocation, EthereumNetwork, xcm::v5::Location>,
 			xcm_config::bridging::to_rococo::RococoAssetFromAssetHubRococo,
 		),
 		LocationToAccountId,
 		AccountId,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	>;
 	type ForceOrigin = AssetsForceOrigin;
 	type AssetDeposit = ForeignAssetsAssetDeposit;
@@ -810,7 +810,7 @@ parameter_types! {
 
 impl pallet_asset_conversion_tx_payment::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
-	type AssetId = xcm::v4::Location;
+	type AssetId = xcm::v5::Location;
 	type OnChargeAssetTransaction = SwapAssetAdapter<
 		WestendLocation,
 		NativeAndAssets,
@@ -1485,18 +1485,18 @@ impl_runtime_apis! {
 	impl pallet_asset_conversion::AssetConversionApi<
 		Block,
 		Balance,
-		xcm::v4::Location,
+		xcm::v5::Location,
 	> for Runtime
 	{
-		fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
+		fn quote_price_exact_tokens_for_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
 			AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee)
 		}
 
-		fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
+		fn quote_price_tokens_for_exact_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
 			AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee)
 		}
 
-		fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> {
+		fn get_reserves(asset1: xcm::v5::Location, asset2: xcm::v5::Location) -> Option<(Balance, Balance)> {
 			AssetConversion::get_reserves(asset1, asset2).ok()
 		}
 	}
@@ -1530,7 +1530,7 @@ impl_runtime_apis! {
 			// We also accept all assets in a pool with the native token.
 			let assets_in_pool_with_native = assets_common::get_assets_in_pool_with::<
 				Runtime,
-				xcm::v4::Location
+				xcm::v5::Location
 			>(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter();
 			acceptable_assets.extend(assets_in_pool_with_native);
 			PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets)
@@ -1548,7 +1548,7 @@ impl_runtime_apis! {
 					// We recognize assets in a pool with the native one.
 					let assets_in_pool_with_this_asset: Vec<_> = assets_common::get_assets_in_pool_with::<
 						Runtime,
-						xcm::v4::Location
+						xcm::v5::Location
 					>(&asset_id.0).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?;
 					if assets_in_pool_with_this_asset
 						.into_iter()
@@ -2000,7 +2000,7 @@ impl_runtime_apis! {
 				fn fee_asset() -> Result<Asset, BenchmarkError> {
 					Ok(Asset {
 						id: AssetId(WestendLocation::get()),
-						fun: Fungible(1_000_000 * UNITS),
+						fun: Fungible(1_000 * UNITS),
 					})
 				}
 
@@ -2014,7 +2014,12 @@ impl_runtime_apis! {
 				}
 
 				fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
-					Err(BenchmarkError::Skip)
+					// Any location can alias to an internal location.
+					// Here parachain 1001 aliases to an internal account.
+					Ok((
+						Location::new(1, [Parachain(1001)]),
+						Location::new(1, [Parachain(1001), AccountId32 { id: [111u8; 32], network: None }]),
+					))
 				}
 			}
 
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
index d39052c5c03..928f1910cbd 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
@@ -21,7 +21,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -80,11 +83,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -132,12 +131,35 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -150,6 +172,9 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 	fn clear_error() -> Weight {
 		XcmGeneric::<Runtime>::clear_error()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 	fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight {
 		XcmGeneric::<Runtime>::claim_asset()
 	}
@@ -223,8 +248,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 		XcmGeneric::<Runtime>::clear_topic()
 	}
 	fn alias_origin(_: &Location) -> Weight {
-		// XCM Executor does not currently support alias origin operations
-		Weight::MAX
+		XcmGeneric::<Runtime>::alias_origin()
 	}
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 0aeae318462..97e59c24dd8 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 32_651_000 picoseconds.
-		Weight::from_parts(33_225_000, 3593)
+		// Minimum execution time: 32_698_000 picoseconds.
+		Weight::from_parts(33_530_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 41_059_000 picoseconds.
-		Weight::from_parts(41_730_000, 6196)
+		// Minimum execution time: 41_485_000 picoseconds.
+		Weight::from_parts(41_963_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -90,8 +90,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `8799`
-		// Minimum execution time: 102_780_000 picoseconds.
-		Weight::from_parts(105_302_000, 8799)
+		// Minimum execution time: 104_952_000 picoseconds.
+		Weight::from_parts(108_211_000, 8799)
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
@@ -99,8 +99,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_124_000 picoseconds.
-		Weight::from_parts(1_201_000, 0)
+		// Minimum execution time: 1_154_000 picoseconds.
+		Weight::from_parts(1_238_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -122,8 +122,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 109_024_000 picoseconds.
-		Weight::from_parts(111_406_000, 6196)
+		// Minimum execution time: 111_509_000 picoseconds.
+		Weight::from_parts(114_476_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -131,8 +131,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_887_000 picoseconds.
-		Weight::from_parts(3_081_000, 0)
+		// Minimum execution time: 2_572_000 picoseconds.
+		Weight::from_parts(2_809_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -140,8 +140,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 25_234_000 picoseconds.
-		Weight::from_parts(25_561_000, 3593)
+		// Minimum execution time: 25_570_000 picoseconds.
+		Weight::from_parts(25_933_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -165,8 +165,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `6196`
-		// Minimum execution time: 83_416_000 picoseconds.
-		Weight::from_parts(85_683_000, 6196)
+		// Minimum execution time: 86_148_000 picoseconds.
+		Weight::from_parts(88_170_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -190,9 +190,34 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 49_271_000 picoseconds.
-		Weight::from_parts(51_019_000, 3610)
+		// Minimum execution time: 55_051_000 picoseconds.
+		Weight::from_parts(56_324_000, 3610)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
+	// Storage: `System::Account` (r:2 w:2)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `145`
+		//  Estimated: `6196`
+		// Minimum execution time: 90_155_000 picoseconds.
+		Weight::from_parts(91_699_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(9))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 98ecd7bd309..7098f175d42 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -68,8 +68,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 100_823_000 picoseconds.
-		Weight::from_parts(103_071_000, 6196)
+		// Minimum execution time: 103_794_000 picoseconds.
+		Weight::from_parts(106_697_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -77,8 +77,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 600_000 picoseconds.
-		Weight::from_parts(686_000, 0)
+		// Minimum execution time: 621_000 picoseconds.
+		Weight::from_parts(705_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 5_580_000 picoseconds.
+		Weight::from_parts(5_950_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 598_000 picoseconds.
+		Weight::from_parts(700_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -86,58 +100,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3568`
-		// Minimum execution time: 8_226_000 picoseconds.
-		Weight::from_parts(8_650_000, 3568)
+		// Minimum execution time: 8_186_000 picoseconds.
+		Weight::from_parts(8_753_000, 3568)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_131_000 picoseconds.
-		Weight::from_parts(7_600_000, 0)
+		// Minimum execution time: 6_924_000 picoseconds.
+		Weight::from_parts(7_315_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_589_000 picoseconds.
-		Weight::from_parts(2_705_000, 0)
+		// Minimum execution time: 2_731_000 picoseconds.
+		Weight::from_parts(2_828_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 667_000 picoseconds.
-		Weight::from_parts(744_000, 0)
+		// Minimum execution time: 655_000 picoseconds.
+		Weight::from_parts(723_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 646_000 picoseconds.
-		Weight::from_parts(720_000, 0)
+		// Minimum execution time: 648_000 picoseconds.
+		Weight::from_parts(730_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 633_000 picoseconds.
-		Weight::from_parts(669_000, 0)
+		// Minimum execution time: 628_000 picoseconds.
+		Weight::from_parts(697_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 671_000 picoseconds.
-		Weight::from_parts(726_000, 0)
+		// Minimum execution time: 714_000 picoseconds.
+		Weight::from_parts(775_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 615_000 picoseconds.
-		Weight::from_parts(675_000, 0)
+		// Minimum execution time: 666_000 picoseconds.
+		Weight::from_parts(717_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -159,8 +173,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_236_000 picoseconds.
-		Weight::from_parts(69_899_000, 6196)
+		// Minimum execution time: 70_263_000 picoseconds.
+		Weight::from_parts(71_266_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -170,8 +184,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `160`
 		//  Estimated: `3625`
-		// Minimum execution time: 12_976_000 picoseconds.
-		Weight::from_parts(13_357_000, 3625)
+		// Minimum execution time: 13_079_000 picoseconds.
+		Weight::from_parts(13_569_000, 3625)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -179,8 +193,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 633_000 picoseconds.
-		Weight::from_parts(685_000, 0)
+		// Minimum execution time: 630_000 picoseconds.
+		Weight::from_parts(710_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -200,8 +214,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `145`
 		//  Estimated: `3610`
-		// Minimum execution time: 28_707_000 picoseconds.
-		Weight::from_parts(31_790_000, 3610)
+		// Minimum execution time: 29_042_000 picoseconds.
+		Weight::from_parts(29_633_000, 3610)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -211,44 +225,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_670_000 picoseconds.
-		Weight::from_parts(2_833_000, 0)
+		// Minimum execution time: 2_601_000 picoseconds.
+		Weight::from_parts(2_855_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 23_459_000 picoseconds.
-		Weight::from_parts(23_817_000, 0)
+		// Minimum execution time: 23_696_000 picoseconds.
+		Weight::from_parts(24_427_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_197_000 picoseconds.
-		Weight::from_parts(6_338_000, 0)
+		// Minimum execution time: 6_687_000 picoseconds.
+		Weight::from_parts(6_820_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 671_000 picoseconds.
-		Weight::from_parts(715_000, 0)
+		// Minimum execution time: 653_000 picoseconds.
+		Weight::from_parts(728_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 655_000 picoseconds.
-		Weight::from_parts(694_000, 0)
+		// Minimum execution time: 668_000 picoseconds.
+		Weight::from_parts(721_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 810_000 picoseconds.
-		Weight::from_parts(858_000, 0)
+		// Minimum execution time: 832_000 picoseconds.
+		Weight::from_parts(900_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -270,8 +284,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 73_136_000 picoseconds.
-		Weight::from_parts(75_314_000, 6196)
+		// Minimum execution time: 75_131_000 picoseconds.
+		Weight::from_parts(77_142_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -279,8 +293,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_515_000 picoseconds.
-		Weight::from_parts(4_768_000, 0)
+		// Minimum execution time: 4_820_000 picoseconds.
+		Weight::from_parts(5_089_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -302,8 +316,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `246`
 		//  Estimated: `6196`
-		// Minimum execution time: 68_072_000 picoseconds.
-		Weight::from_parts(69_866_000, 6196)
+		// Minimum execution time: 70_079_000 picoseconds.
+		Weight::from_parts(71_762_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -311,22 +325,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 696_000 picoseconds.
-		Weight::from_parts(736_000, 0)
+		// Minimum execution time: 722_000 picoseconds.
+		Weight::from_parts(784_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 618_000 picoseconds.
-		Weight::from_parts(681_000, 0)
+		// Minimum execution time: 613_000 picoseconds.
+		Weight::from_parts(674_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 647_000 picoseconds.
-		Weight::from_parts(672_000, 0)
+		// Minimum execution time: 608_000 picoseconds.
+		Weight::from_parts(683_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -334,22 +348,29 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `1489`
-		// Minimum execution time: 2_496_000 picoseconds.
-		Weight::from_parts(2_617_000, 1489)
+		// Minimum execution time: 2_466_000 picoseconds.
+		Weight::from_parts(2_705_000, 1489)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 637_000 picoseconds.
-		Weight::from_parts(675_000, 0)
+		// Minimum execution time: 623_000 picoseconds.
+		Weight::from_parts(687_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 607_000 picoseconds.
-		Weight::from_parts(683_000, 0)
+		// Minimum execution time: 673_000 picoseconds.
+		Weight::from_parts(752_000, 0)
+	}
+	pub fn alias_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 638_000 picoseconds.
+		Weight::from_parts(708_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs
index f16dbcc0251..88ccd42dff7 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs
@@ -28,7 +28,7 @@ use frame_support::{
 	parameter_types,
 	traits::{
 		tokens::imbalance::{ResolveAssetTo, ResolveTo},
-		ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess,
+		ConstU32, Contains, Equals, Everything, PalletInfoAccess,
 	},
 };
 use frame_system::EnsureRoot;
@@ -44,26 +44,27 @@ 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::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
 use xcm_builder::{
-	AccountId32Aliases, 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,
+	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 WestendLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Westend);
+	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();
@@ -171,7 +172,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte
 		StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
 	),
 	Balance,
-	xcm::v4::Location,
+	xcm::v5::Location,
 >;
 
 /// Means for transacting foreign assets from different global consensus.
@@ -358,14 +359,14 @@ pub type PoolAssetsExchanger = SingleAssetExchangeAdapter<
 	crate::AssetConversion,
 	crate::NativeAndAssets,
 	(
-		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v4::Location>,
+		TrustBackedAssetsAsLocation<TrustBackedAssetsPalletLocation, Balance, xcm::v5::Location>,
 		ForeignAssetsConvertedConcreteId,
 		// `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here.
 		MatchedConvertedConcreteId<
-			xcm::v4::Location,
+			xcm::v5::Location,
 			Balance,
 			Equals<ParentLocation>,
-			WithLatestLocationConverter<xcm::v4::Location>,
+			WithLatestLocationConverter<xcm::v5::Location>,
 			TryConvertInto,
 		>,
 	),
@@ -411,7 +412,7 @@ impl xcm_executor::Config for XcmConfig {
 				TrustBackedAssetsAsLocation<
 					TrustBackedAssetsPalletLocation,
 					Balance,
-					xcm::v4::Location,
+					xcm::v5::Location,
 				>,
 				ForeignAssetsConvertedConcreteId,
 			),
@@ -462,7 +463,8 @@ impl xcm_executor::Config for XcmConfig {
 		(bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases);
 	type CallDispatcher = RuntimeCall;
 	type SafeCallFilter = Everything;
-	type Aliasers = Nothing;
+	// We allow any origin to alias into a child sub-location (equivalent to DescendOrigin).
+	type Aliasers = AliasChildLocation;
 	type TransactionalProcessor = FrameTransactionalProcessor;
 	type HrmpNewChannelOpenRequestHandler = ();
 	type HrmpChannelAcceptedHandler = ();
@@ -538,9 +540,9 @@ impl cumulus_pallet_xcm::Config for Runtime {
 /// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
 pub struct XcmBenchmarkHelper;
 #[cfg(feature = "runtime-benchmarks")]
-impl pallet_assets::BenchmarkHelper<xcm::v4::Location> for XcmBenchmarkHelper {
-	fn create_asset_id_parameter(id: u32) -> xcm::v4::Location {
-		xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)])
+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)])
 	}
 }
 
@@ -596,7 +598,7 @@ pub mod bridging {
 				]
 			);
 
-			pub const RococoNetwork: NetworkId = NetworkId::Rococo;
+			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, [
@@ -667,7 +669,7 @@ pub mod bridging {
 			/// `Option<Asset>` represents static "base fee" which is used for total delivery fee calculation.
 			pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec![
 				NetworkExportTableItem::new(
-					EthereumNetwork::get(),
+					EthereumNetwork::get().into(),
 					Some(sp_std::vec![Junctions::Here]),
 					SiblingBridgeHub::get(),
 					Some((
@@ -680,7 +682,7 @@ pub mod bridging {
 			/// Universal aliases
 			pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter(
 				sp_std::vec![
-					(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())),
+					(SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())),
 				]
 			);
 
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs
index 6a48b19ce94..5d0f843554a 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs
@@ -52,7 +52,10 @@ use sp_core::crypto::Ss58Codec;
 use sp_runtime::traits::MaybeEquivalence;
 use std::{convert::Into, ops::Mul};
 use testnet_parachains_constants::westend::{consensus::*, currency::UNITS, fee::WeightToFee};
-use xcm::latest::prelude::{Assets as XcmAssets, *};
+use xcm::latest::{
+	prelude::{Assets as XcmAssets, *},
+	ROCOCO_GENESIS_HASH,
+};
 use xcm_builder::WithLatestLocationConverter;
 use xcm_executor::traits::{ConvertLocation, JustTry, WeightTrader};
 use xcm_runtime_apis::conversions::LocationToAccountHelper;
@@ -87,7 +90,7 @@ fn slot_durations() -> SlotDurations {
 fn setup_pool_for_paying_fees_with_foreign_assets(
 	(foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): (
 		AccountId,
-		xcm::v4::Location,
+		xcm::v5::Location,
 		Balance,
 	),
 ) {
@@ -95,7 +98,7 @@ fn setup_pool_for_paying_fees_with_foreign_assets(
 
 	// setup a pool to pay fees with `foreign_asset_id_location` tokens
 	let pool_owner: AccountId = [14u8; 32].into();
-	let native_asset = xcm::v4::Location::parent();
+	let native_asset = xcm::v5::Location::parent();
 	let pool_liquidity: Balance =
 		existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000);
 
@@ -220,10 +223,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() {
 			assert_ok!(AssetConversion::create_pool(
 				RuntimeHelper::origin_of(bob.clone()),
 				Box::new(
-					xcm::v4::Location::try_from(native_location.clone()).expect("conversion works")
+					xcm::v5::Location::try_from(native_location.clone()).expect("conversion works")
 				),
 				Box::new(
-					xcm::v4::Location::try_from(asset_1_location.clone())
+					xcm::v5::Location::try_from(asset_1_location.clone())
 						.expect("conversion works")
 				)
 			));
@@ -231,10 +234,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() {
 			assert_ok!(AssetConversion::add_liquidity(
 				RuntimeHelper::origin_of(bob.clone()),
 				Box::new(
-					xcm::v4::Location::try_from(native_location.clone()).expect("conversion works")
+					xcm::v5::Location::try_from(native_location.clone()).expect("conversion works")
 				),
 				Box::new(
-					xcm::v4::Location::try_from(asset_1_location.clone())
+					xcm::v5::Location::try_from(asset_1_location.clone())
 						.expect("conversion works")
 				),
 				pool_liquidity,
@@ -272,8 +275,8 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() {
 			let refund_weight = Weight::from_parts(1_000_000_000, 0);
 			let refund = WeightToFee::weight_to_fee(&refund_weight);
 			let (reserve1, reserve2) = AssetConversion::get_reserves(
-				xcm::v4::Location::try_from(native_location).expect("conversion works"),
-				xcm::v4::Location::try_from(asset_1_location.clone()).expect("conversion works"),
+				xcm::v5::Location::try_from(native_location).expect("conversion works"),
+				xcm::v5::Location::try_from(asset_1_location.clone()).expect("conversion works"),
 			)
 			.unwrap();
 			let asset_refund =
@@ -311,12 +314,12 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() {
 			let bob: AccountId = SOME_ASSET_ADMIN.into();
 			let staking_pot = CollatorSelection::account_id();
 			let native_location =
-				xcm::v4::Location::try_from(WestendLocation::get()).expect("conversion works");
-			let foreign_location = xcm::v4::Location {
+				xcm::v5::Location::try_from(WestendLocation::get()).expect("conversion works");
+			let foreign_location = xcm::v5::Location {
 				parents: 1,
 				interior: (
-					xcm::v4::Junction::Parachain(1234),
-					xcm::v4::Junction::GeneralIndex(12345),
+					xcm::v5::Junction::Parachain(1234),
+					xcm::v5::Junction::GeneralIndex(12345),
 				)
 					.into(),
 			};
@@ -498,11 +501,11 @@ fn test_foreign_asset_xcm_take_first_trader() {
 		.execute_with(|| {
 			// We need root origin to create a sufficient asset
 			let minimum_asset_balance = 3333333_u128;
-			let foreign_location = xcm::v4::Location {
+			let foreign_location = xcm::v5::Location {
 				parents: 1,
 				interior: (
-					xcm::v4::Junction::Parachain(1234),
-					xcm::v4::Junction::GeneralIndex(12345),
+					xcm::v5::Junction::Parachain(1234),
+					xcm::v5::Junction::GeneralIndex(12345),
 				)
 					.into(),
 			};
@@ -522,7 +525,7 @@ fn test_foreign_asset_xcm_take_first_trader() {
 				minimum_asset_balance
 			));
 
-			let asset_location_v4: Location = foreign_location.clone().try_into().unwrap();
+			let asset_location_v5: Location = foreign_location.clone().try_into().unwrap();
 
 			// Set Alice as block author, who will receive fees
 			RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
@@ -537,7 +540,7 @@ fn test_foreign_asset_xcm_take_first_trader() {
 			// Lets pay with: asset_amount_needed + asset_amount_extra
 			let asset_amount_extra = 100_u128;
 			let asset: Asset =
-				(asset_location_v4.clone(), asset_amount_needed + asset_amount_extra).into();
+				(asset_location_v5.clone(), asset_amount_needed + asset_amount_extra).into();
 
 			let mut trader = <XcmConfig as xcm_executor::Config>::Trader::new();
 			let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
@@ -546,7 +549,7 @@ fn test_foreign_asset_xcm_take_first_trader() {
 			let unused_assets = trader.buy_weight(bought, asset.into(), &ctx).expect("Expected Ok");
 			// Check whether a correct amount of unused assets is returned
 			assert_ok!(
-				unused_assets.ensure_contains(&(asset_location_v4, asset_amount_extra).into())
+				unused_assets.ensure_contains(&(asset_location_v5, asset_amount_extra).into())
 			);
 
 			// Drop trader
@@ -834,11 +837,11 @@ fn test_assets_balances_api_works() {
 		.build()
 		.execute_with(|| {
 			let local_asset_id = 1;
-			let foreign_asset_id_location = xcm::v4::Location {
+			let foreign_asset_id_location = xcm::v5::Location {
 				parents: 1,
 				interior: [
-					xcm::v4::Junction::Parachain(1234),
-					xcm::v4::Junction::GeneralIndex(12345),
+					xcm::v5::Junction::Parachain(1234),
+					xcm::v5::Junction::GeneralIndex(12345),
 				]
 				.into(),
 			};
@@ -929,7 +932,7 @@ fn test_assets_balances_api_works() {
 				.into())));
 			// check foreign asset
 			assert!(result.inner().iter().any(|asset| asset.eq(&(
-				WithLatestLocationConverter::<xcm::v4::Location>::convert_back(
+				WithLatestLocationConverter::<xcm::v5::Location>::convert_back(
 					&foreign_asset_id_location
 				)
 				.unwrap(),
@@ -1022,13 +1025,13 @@ asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_
 	Runtime,
 	XcmConfig,
 	ForeignAssetsInstance,
-	xcm::v4::Location,
+	xcm::v5::Location,
 	JustTry,
 	collator_session_keys(),
 	ExistentialDeposit::get(),
-	xcm::v4::Location {
+	xcm::v5::Location {
 		parents: 1,
-		interior: [xcm::v4::Junction::Parachain(1313), xcm::v4::Junction::GeneralIndex(12345)]
+		interior: [xcm::v5::Junction::Parachain(1313), xcm::v5::Junction::GeneralIndex(12345)]
 			.into()
 	},
 	Box::new(|| {
@@ -1045,8 +1048,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p
 	WeightToFee,
 	LocationToAccountId,
 	ForeignAssetsInstance,
-	xcm::v4::Location,
-	WithLatestLocationConverter<xcm::v4::Location>,
+	xcm::v5::Location,
+	WithLatestLocationConverter<xcm::v5::Location>,
 	collator_session_keys(),
 	ExistentialDeposit::get(),
 	AssetDeposit::get(),
@@ -1123,8 +1126,10 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s
 	let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT);
 	let staking_pot = StakingPot::get();
 
-	let foreign_asset_id_location =
-		xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]);
+	let foreign_asset_id_location = xcm::v5::Location::new(
+		2,
+		[xcm::v5::Junction::GlobalConsensus(xcm::v5::NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))],
+	);
 	let foreign_asset_id_minimum_balance = 1_000_000_000;
 	// sovereign account as foreign asset owner (can be whoever for this scenario)
 	let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap();
@@ -1154,7 +1159,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s
 			},
 			(
 				[PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(),
-				GlobalConsensus(Rococo),
+				GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
 				[Parachain(1000)].into()
 			),
 			|| {
@@ -1192,8 +1197,10 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic
 	let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT);
 	let staking_pot = StakingPot::get();
 
-	let foreign_asset_id_location =
-		xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]);
+	let foreign_asset_id_location = xcm::v5::Location::new(
+		2,
+		[xcm::v5::Junction::GlobalConsensus(xcm::v5::NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))],
+	);
 	let foreign_asset_id_minimum_balance = 1_000_000_000;
 	// sovereign account as foreign asset owner (can be whoever for this scenario)
 	let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap();
@@ -1216,7 +1223,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic
 		bridging_to_asset_hub_rococo,
 		(
 			[PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(),
-			GlobalConsensus(Rococo),
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
 			[Parachain(1000)].into()
 		),
 		|| {
diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs
index 26046e5974b..1d2d45b42c5 100644
--- a/cumulus/parachains/runtimes/assets/common/src/lib.rs
+++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs
@@ -293,15 +293,15 @@ mod tests {
 			pub UniversalLocationNetworkId: NetworkId = NetworkId::ByGenesis([9; 32]);
 		}
 
-		// set up a converter which uses `xcm::v3::Location` under the hood
+		// set up a converter which uses `xcm::v4::Location` under the hood
 		type Convert = ForeignAssetsConvertedConcreteId<
 			(
 				StartsWith<Parachain100Pattern>,
 				StartsWithExplicitGlobalConsensus<UniversalLocationNetworkId>,
 			),
 			u128,
-			xcm::v3::Location,
-			WithLatestLocationConverter<xcm::v3::Location>,
+			xcm::v4::Location,
+			WithLatestLocationConverter<xcm::v4::Location>,
 		>;
 
 		let test_data = vec![
@@ -348,18 +348,18 @@ mod tests {
 			// ok
 			(
 				ma_1000(1, [Parachain(200)].into()),
-				Ok((xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(200)]), 1000)),
+				Ok((xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(200)]), 1000)),
 			),
 			(
 				ma_1000(2, [Parachain(200)].into()),
-				Ok((xcm::v3::Location::new(2, [xcm::v3::Junction::Parachain(200)]), 1000)),
+				Ok((xcm::v4::Location::new(2, [xcm::v4::Junction::Parachain(200)]), 1000)),
 			),
 			(
 				ma_1000(1, [Parachain(200), GeneralIndex(1234)].into()),
 				Ok((
-					xcm::v3::Location::new(
+					xcm::v4::Location::new(
 						1,
-						[xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)],
+						[xcm::v4::Junction::Parachain(200), xcm::v4::Junction::GeneralIndex(1234)],
 					),
 					1000,
 				)),
@@ -367,9 +367,9 @@ mod tests {
 			(
 				ma_1000(2, [Parachain(200), GeneralIndex(1234)].into()),
 				Ok((
-					xcm::v3::Location::new(
+					xcm::v4::Location::new(
 						2,
-						[xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)],
+						[xcm::v4::Junction::Parachain(200), xcm::v4::Junction::GeneralIndex(1234)],
 					),
 					1000,
 				)),
@@ -377,9 +377,9 @@ mod tests {
 			(
 				ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([7; 32]))].into()),
 				Ok((
-					xcm::v3::Location::new(
+					xcm::v4::Location::new(
 						2,
-						[xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis(
+						[xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis(
 							[7; 32],
 						))],
 					),
@@ -397,14 +397,14 @@ mod tests {
 					.into(),
 				),
 				Ok((
-					xcm::v3::Location::new(
+					xcm::v4::Location::new(
 						2,
 						[
-							xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis(
+							xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis(
 								[7; 32],
 							)),
-							xcm::v3::Junction::Parachain(200),
-							xcm::v3::Junction::GeneralIndex(1234),
+							xcm::v4::Junction::Parachain(200),
+							xcm::v4::Junction::GeneralIndex(1234),
 						],
 					),
 					1000,
@@ -414,7 +414,7 @@ mod tests {
 
 		for (asset, expected_result) in test_data {
 			assert_eq!(
-				<Convert as MatchesFungibles<xcm::v3::Location, u128>>::matches_fungibles(
+				<Convert as MatchesFungibles<xcm::v4::Location, u128>>::matches_fungibles(
 					&asset.clone().try_into().unwrap()
 				),
 				expected_result,
diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs
index 5a452f6eed1..aa9d7929cb9 100644
--- a/cumulus/parachains/runtimes/assets/common/src/matching.rs
+++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs
@@ -146,10 +146,11 @@ impl<AssetsAllowedNetworks: Contains<Location>, OriginLocation: Get<Location>>
 mod tests {
 	use super::*;
 	use frame_support::parameter_types;
+	use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH};
 
 	parameter_types! {
-		pub UniversalLocation: InteriorLocation = [GlobalConsensus(Rococo), Parachain(1000)].into();
-		pub ExpectedNetworkId: NetworkId = Westend;
+		pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)].into();
+		pub ExpectedNetworkId: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
 	}
 
 	#[test]
@@ -158,26 +159,30 @@ mod tests {
 		let asset: Location = (
 			Parent,
 			Parent,
-			GlobalConsensus(Westend),
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 			Parachain(1000),
 			PalletInstance(1),
 			GeneralIndex(1),
 		)
 			.into();
-		let origin: Location = (Parent, Parent, GlobalConsensus(Westend), Parachain(1000)).into();
+		let origin: Location =
+			(Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
+				.into();
 		assert!(FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
 
 		// asset and origin from local consensus fails
 		let asset: Location = (
 			Parent,
 			Parent,
-			GlobalConsensus(Rococo),
+			GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)),
 			Parachain(1000),
 			PalletInstance(1),
 			GeneralIndex(1),
 		)
 			.into();
-		let origin: Location = (Parent, Parent, GlobalConsensus(Rococo), Parachain(1000)).into();
+		let origin: Location =
+			(Parent, Parent, GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000))
+				.into();
 		assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
 
 		// asset and origin from here fails
@@ -195,14 +200,16 @@ mod tests {
 			GeneralIndex(1),
 		)
 			.into();
-		let origin: Location = (Parent, Parent, GlobalConsensus(Westend), Parachain(1000)).into();
+		let origin: Location =
+			(Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000))
+				.into();
 		assert!(!FromNetwork::<UniversalLocation, ExpectedNetworkId>::contains(&asset, &origin));
 
 		// origin from different consensus fails
 		let asset: Location = (
 			Parent,
 			Parent,
-			GlobalConsensus(Westend),
+			GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),
 			Parachain(1000),
 			PalletInstance(1),
 			GeneralIndex(1),
diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
index c8022214230..8dc720e2775 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
@@ -367,9 +367,9 @@ pub fn teleports_for_foreign_assets_works<
 	<WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
 	SovereignAccountOf: ConvertLocation<AccountIdOf<Runtime>>,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetId:
-		From<xcm::v4::Location> + Into<xcm::v4::Location>,
+		From<xcm::v5::Location> + Into<xcm::v5::Location>,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetIdParameter:
-		From<xcm::v4::Location> + Into<xcm::v4::Location>,
+		From<xcm::v5::Location> + Into<xcm::v5::Location>,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::Balance:
 		From<Balance> + Into<u128>,
 	<Runtime as frame_system::Config>::AccountId:
@@ -381,11 +381,11 @@ pub fn teleports_for_foreign_assets_works<
 {
 	// foreign parachain with the same consensus currency as asset
 	let foreign_para_id = 2222;
-	let foreign_asset_id_location = xcm::v4::Location {
+	let foreign_asset_id_location = xcm::v5::Location {
 		parents: 1,
 		interior: [
-			xcm::v4::Junction::Parachain(foreign_para_id),
-			xcm::v4::Junction::GeneralIndex(1234567),
+			xcm::v5::Junction::Parachain(foreign_para_id),
+			xcm::v5::Junction::GeneralIndex(1234567),
 		]
 		.into(),
 	};
@@ -1202,19 +1202,13 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
 			let xcm = Xcm(vec![
 				WithdrawAsset(buy_execution_fee.clone().into()),
 				BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
-				Transact {
-					origin_kind: OriginKind::Xcm,
-					require_weight_at_most: Weight::from_parts(40_000_000_000, 8000),
-					call: foreign_asset_create.into(),
-				},
+				Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() },
 				Transact {
 					origin_kind: OriginKind::SovereignAccount,
-					require_weight_at_most: Weight::from_parts(20_000_000_000, 8000),
 					call: foreign_asset_set_metadata.into(),
 				},
 				Transact {
 					origin_kind: OriginKind::SovereignAccount,
-					require_weight_at_most: Weight::from_parts(20_000_000_000, 8000),
 					call: foreign_asset_set_team.into(),
 				},
 				ExpectTransactStatus(MaybeErrorCode::Success),
@@ -1321,11 +1315,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
 			let xcm = Xcm(vec![
 				WithdrawAsset(buy_execution_fee.clone().into()),
 				BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
-				Transact {
-					origin_kind: OriginKind::Xcm,
-					require_weight_at_most: Weight::from_parts(20_000_000_000, 8000),
-					call: foreign_asset_create.into(),
-				},
+				Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() },
 				ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())),
 			]);
 
diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
index d8676117474..4f144e24aa3 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
@@ -331,7 +331,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works<
 	block_author_account: AccountIdOf<Runtime>,
 	(foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): (
 		AccountIdOf<Runtime>,
-		xcm::v4::Location,
+		xcm::v5::Location,
 		u128,
 	),
 	foreign_asset_id_amount_to_transfer: u128,
@@ -357,9 +357,9 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works<
 	BalanceOf<Runtime>: From<Balance> + Into<Balance>,
 	XcmConfig: xcm_executor::Config,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetId:
-		From<xcm::v4::Location> + Into<xcm::v4::Location>,
+		From<xcm::v5::Location> + Into<xcm::v5::Location>,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetIdParameter:
-		From<xcm::v4::Location> + Into<xcm::v4::Location>,
+		From<xcm::v5::Location> + Into<xcm::v5::Location>,
 	<Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::Balance:
 		From<Balance> + Into<u128> + From<u128>,
 	<Runtime as frame_system::Config>::AccountId: Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs
index c226ed9c4fa..7e038569237 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs
@@ -246,12 +246,13 @@ where
 {
 	use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState};
 	use sp_runtime::traits::Zero;
-	use xcm::VersionedInteriorLocation;
+	use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation};
 
 	// insert bridge metadata
 	let lane_id = with;
 	let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]);
-	let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into();
+	let universal_source =
+		[GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into();
 	let universal_destination =
 		[GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get()), Parachain(2075)].into();
 	let bridge_id = BridgeId::new(&universal_source, &universal_destination);
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs
index 29ea4e05f29..0eab3c74a7e 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs
@@ -43,14 +43,14 @@ use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSyst
 use polkadot_parachain_primitives::primitives::Sibling;
 use testnet_parachains_constants::rococo::currency::UNITS as ROC;
 use xcm::{
-	latest::prelude::*,
+	latest::{prelude::*, WESTEND_GENESIS_HASH},
 	prelude::{InteriorLocation, NetworkId},
 };
 use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia};
 
 parameter_types! {
 	pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(<BridgeWestendMessages as PalletInfoAccess>::index() as u8)].into();
-	pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend;
+	pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
 	pub WestendGlobalConsensusNetworkLocation: Location = Location::new(
 		2,
 		[GlobalConsensus(WestendGlobalConsensusNetwork::get())]
@@ -175,13 +175,15 @@ where
 {
 	use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState};
 	use sp_runtime::traits::Zero;
-	use xcm::VersionedInteriorLocation;
+	use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation};
 
 	// insert bridge metadata
 	let lane_id = with;
 	let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]);
-	let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into();
-	let universal_destination = [GlobalConsensus(Westend), Parachain(2075)].into();
+	let universal_source =
+		[GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into();
+	let universal_destination =
+		[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2075)].into();
 	let bridge_id = BridgeId::new(&universal_source, &universal_destination);
 
 	// insert only bridge metadata, because the benchmarks create lanes
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs
index 8b749ae301b..20ca88bbc54 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs
@@ -22,6 +22,7 @@ use parachains_common::{AccountId, AuraId};
 use sp_genesis_builder::PresetId;
 use sp_keyring::Sr25519Keyring;
 use testnet_parachains_constants::rococo::xcm_version::SAFE_XCM_VERSION;
+use xcm::latest::WESTEND_GENESIS_HASH;
 
 const BRIDGE_HUB_ROCOCO_ED: Balance = ExistentialDeposit::get();
 
@@ -102,7 +103,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option<sp_std::vec::Vec<
 			rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(),
 			vec![(
 				Location::new(1, [Parachain(1000)]),
-				Junctions::from([Westend.into(), Parachain(1000)]),
+				Junctions::from([ByGenesis(WESTEND_GENESIS_HASH).into(), Parachain(1000)]),
 				Some(bp_messages::LegacyLaneId([0, 0, 0, 2])),
 			)],
 		),
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
index 9a44dd17b64..ff7af475f5e 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
@@ -80,6 +80,9 @@ use bridge_hub_common::{
 };
 pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
 pub use sp_runtime::{MultiAddress, Perbill, Permill};
+
+#[cfg(feature = "runtime-benchmarks")]
+use xcm::latest::WESTEND_GENESIS_HASH;
 use xcm::VersionedLocation;
 use xcm_config::{TreasuryAccount, XcmOriginToTransactDispatchOrigin, XcmRouter};
 
@@ -1270,7 +1273,7 @@ impl_runtime_apis! {
 					);
 
 					// open bridge
-					let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(8765)].into();
+					let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)), Parachain(8765)].into();
 					let locations = XcmOverBridgeHubWestend::bridge_locations(
 						sibling_parachain_location.clone(),
 						bridge_destination_universal_location.clone(),
@@ -1292,7 +1295,7 @@ impl_runtime_apis! {
 					Ok(
 						(
 							sibling_parachain_location,
-							NetworkId::Westend,
+							NetworkId::ByGenesis(WESTEND_GENESIS_HASH),
 							[Parachain(8765)].into()
 						)
 					)
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
index b40cbfeeb8f..60a0fc005ca 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
@@ -22,7 +22,10 @@ use codec::Encode;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -81,11 +84,7 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -133,12 +132,35 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubRococoXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -231,4 +253,7 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubRococoXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index f2cee0e3e80..4a5623fc8b9 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_988_000 picoseconds.
-		Weight::from_parts(31_496_000, 3593)
+		// Minimum execution time: 32_488_000 picoseconds.
+		Weight::from_parts(33_257_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `6196`
-		// Minimum execution time: 42_805_000 picoseconds.
-		Weight::from_parts(44_207_000, 6196)
+		// Minimum execution time: 46_250_000 picoseconds.
+		Weight::from_parts(46_856_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -90,8 +90,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `223`
 		//  Estimated: `8799`
-		// Minimum execution time: 103_376_000 picoseconds.
-		Weight::from_parts(104_770_000, 8799)
+		// Minimum execution time: 106_863_000 picoseconds.
+		Weight::from_parts(109_554_000, 8799)
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
@@ -124,8 +124,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `171`
 		//  Estimated: `6196`
-		// Minimum execution time: 71_234_000 picoseconds.
-		Weight::from_parts(72_990_000, 6196)
+		// Minimum execution time: 74_835_000 picoseconds.
+		Weight::from_parts(75_993_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -133,8 +133,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_636_000 picoseconds.
-		Weight::from_parts(2_777_000, 0)
+		// Minimum execution time: 2_709_000 picoseconds.
+		Weight::from_parts(2_901_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -142,8 +142,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `52`
 		//  Estimated: `3593`
-		// Minimum execution time: 23_839_000 picoseconds.
-		Weight::from_parts(24_568_000, 3593)
+		// Minimum execution time: 25_194_000 picoseconds.
+		Weight::from_parts(25_805_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -167,8 +167,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `122`
 		//  Estimated: `6196`
-		// Minimum execution time: 78_345_000 picoseconds.
-		Weight::from_parts(80_558_000, 6196)
+		// Minimum execution time: 82_570_000 picoseconds.
+		Weight::from_parts(84_060_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -192,9 +192,34 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3593`
-		// Minimum execution time: 46_614_000 picoseconds.
-		Weight::from_parts(47_354_000, 3593)
+		// Minimum execution time: 51_959_000 picoseconds.
+		Weight::from_parts(53_434_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
+	// Storage: `System::Account` (r:2 w:2)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `122`
+		//  Estimated: `6196`
+		// Minimum execution time: 86_918_000 picoseconds.
+		Weight::from_parts(89_460_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(9))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 9a9137c1809..b8bd4c4e2d4 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -68,8 +68,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `171`
 		//  Estimated: `6196`
-		// Minimum execution time: 70_133_000 picoseconds.
-		Weight::from_parts(71_765_000, 6196)
+		// Minimum execution time: 69_010_000 picoseconds.
+		Weight::from_parts(70_067_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -77,8 +77,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 959_000 picoseconds.
-		Weight::from_parts(996_000, 0)
+		// Minimum execution time: 1_069_000 picoseconds.
+		Weight::from_parts(1_116_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 2_011_000 picoseconds.
+		Weight::from_parts(2_095_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -86,58 +93,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 7_537_000 picoseconds.
-		Weight::from_parts(7_876_000, 3497)
+		// Minimum execution time: 7_630_000 picoseconds.
+		Weight::from_parts(7_992_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_774_000 picoseconds.
-		Weight::from_parts(7_895_000, 0)
+		// Minimum execution time: 7_909_000 picoseconds.
+		Weight::from_parts(8_100_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_577_000 picoseconds.
-		Weight::from_parts(1_622_000, 0)
+		// Minimum execution time: 1_749_000 picoseconds.
+		Weight::from_parts(1_841_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 973_000 picoseconds.
-		Weight::from_parts(1_008_000, 0)
+		// Minimum execution time: 1_109_000 picoseconds.
+		Weight::from_parts(1_156_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_027_000 picoseconds.
-		Weight::from_parts(1_052_000, 0)
+		// Minimum execution time: 1_073_000 picoseconds.
+		Weight::from_parts(1_143_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 953_000 picoseconds.
-		Weight::from_parts(992_000, 0)
+		// Minimum execution time: 1_050_000 picoseconds.
+		Weight::from_parts(1_084_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 949_000 picoseconds.
-		Weight::from_parts(1_020_000, 0)
+		// Minimum execution time: 1_060_000 picoseconds.
+		Weight::from_parts(1_114_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 979_000 picoseconds.
-		Weight::from_parts(1_032_000, 0)
+		// Minimum execution time: 1_065_000 picoseconds.
+		Weight::from_parts(1_112_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -159,8 +166,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `171`
 		//  Estimated: `6196`
-		// Minimum execution time: 66_663_000 picoseconds.
-		Weight::from_parts(67_728_000, 6196)
+		// Minimum execution time: 65_538_000 picoseconds.
+		Weight::from_parts(66_943_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -170,8 +177,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 11_074_000 picoseconds.
-		Weight::from_parts(11_439_000, 3555)
+		// Minimum execution time: 10_898_000 picoseconds.
+		Weight::from_parts(11_262_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -179,8 +186,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 943_000 picoseconds.
-		Weight::from_parts(1_021_000, 0)
+		// Minimum execution time: 1_026_000 picoseconds.
+		Weight::from_parts(1_104_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -200,8 +207,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 25_123_000 picoseconds.
-		Weight::from_parts(25_687_000, 3503)
+		// Minimum execution time: 25_133_000 picoseconds.
+		Weight::from_parts(25_526_000, 3503)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -211,44 +218,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_868_000 picoseconds.
-		Weight::from_parts(3_124_000, 0)
+		// Minimum execution time: 2_946_000 picoseconds.
+		Weight::from_parts(3_074_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_378_000 picoseconds.
-		Weight::from_parts(1_458_000, 0)
+		// Minimum execution time: 1_428_000 picoseconds.
+		Weight::from_parts(1_490_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_036_000 picoseconds.
-		Weight::from_parts(1_105_000, 0)
+		// Minimum execution time: 1_158_000 picoseconds.
+		Weight::from_parts(1_222_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 945_000 picoseconds.
-		Weight::from_parts(1_021_000, 0)
+		// Minimum execution time: 1_056_000 picoseconds.
+		Weight::from_parts(1_117_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 931_000 picoseconds.
-		Weight::from_parts(1_006_000, 0)
+		// Minimum execution time: 1_045_000 picoseconds.
+		Weight::from_parts(1_084_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_139_000 picoseconds.
-		Weight::from_parts(1_206_000, 0)
+		// Minimum execution time: 1_224_000 picoseconds.
+		Weight::from_parts(1_268_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -270,8 +277,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `171`
 		//  Estimated: `6196`
-		// Minimum execution time: 72_884_000 picoseconds.
-		Weight::from_parts(74_331_000, 6196)
+		// Minimum execution time: 70_789_000 picoseconds.
+		Weight::from_parts(72_321_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -279,8 +286,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_432_000 picoseconds.
-		Weight::from_parts(4_542_000, 0)
+		// Minimum execution time: 4_521_000 picoseconds.
+		Weight::from_parts(4_649_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -302,8 +309,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `171`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_102_000 picoseconds.
-		Weight::from_parts(68_630_000, 6196)
+		// Minimum execution time: 66_129_000 picoseconds.
+		Weight::from_parts(68_089_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -311,22 +318,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 995_000 picoseconds.
-		Weight::from_parts(1_057_000, 0)
+		// Minimum execution time: 1_094_000 picoseconds.
+		Weight::from_parts(1_157_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 956_000 picoseconds.
-		Weight::from_parts(1_021_000, 0)
+		// Minimum execution time: 1_059_000 picoseconds.
+		Weight::from_parts(1_109_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 944_000 picoseconds.
-		Weight::from_parts(986_000, 0)
+		// Minimum execution time: 1_053_000 picoseconds.
+		Weight::from_parts(1_080_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -343,12 +350,12 @@ impl<T: frame_system::Config> WeightInfo<T> {
 	/// The range of component `x` is `[1, 1000]`.
 	pub fn export_message(x: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `589`
-		//  Estimated: `6529`
-		// Minimum execution time: 58_111_000 picoseconds.
-		Weight::from_parts(59_123_071, 6529)
-			// Standard Error: 167
-			.saturating_add(Weight::from_parts(43_658, 0).saturating_mul(x.into()))
+		//  Measured:  `190`
+		//  Estimated: `6130`
+		// Minimum execution time: 42_081_000 picoseconds.
+		Weight::from_parts(42_977_658, 6130)
+			// Standard Error: 77
+			.saturating_add(Weight::from_parts(44_912, 0).saturating_mul(x.into()))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -356,14 +363,21 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 950_000 picoseconds.
-		Weight::from_parts(1_002_000, 0)
+		// Minimum execution time: 1_041_000 picoseconds.
+		Weight::from_parts(1_084_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 963_000 picoseconds.
-		Weight::from_parts(1_012_000, 0)
+		// Minimum execution time: 1_085_000 picoseconds.
+		Weight::from_parts(1_161_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs
index 2fb186703a8..d36075444f7 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs
@@ -40,7 +40,7 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice;
 use snowbridge_runtime_common::XcmExportFeeToSibling;
 use sp_runtime::traits::AccountIdConversion;
 use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -59,7 +59,7 @@ use xcm_executor::{
 parameter_types! {
 	pub const TokenLocation: Location = Location::parent();
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
-	pub RelayNetwork: NetworkId = NetworkId::Rococo;
+	pub RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub UniversalLocation: InteriorLocation =
 		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
 	pub const MaxInstructions: u32 = 100;
@@ -296,7 +296,7 @@ impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
 	fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool {
 		let Some(loc) = origin else { return false };
 		if let Export { network, destination: Here } = fee_reason {
-			if network == EthereumNetwork::get() {
+			if network == EthereumNetwork::get().into() {
 				return false
 			}
 		}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
index 01674287fde..2e7dd98e9dc 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
@@ -37,7 +37,7 @@ use sp_runtime::{
 	AccountId32, Perbill,
 };
 use testnet_parachains_constants::rococo::{consensus::*, fee::WeightToFee};
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_runtime_apis::conversions::LocationToAccountHelper;
 
 parameter_types! {
@@ -377,7 +377,7 @@ mod bridge_hub_westend_tests {
 			bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 			bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
 			SIBLING_PARACHAIN_ID,
-			Rococo,
+			ByGenesis(ROCOCO_GENESIS_HASH),
 			|| {
 				// we need to create lane between sibling parachain and remote destination
 				bridge_hub_test_utils::ensure_opened_bridge::<
@@ -411,7 +411,7 @@ mod bridge_hub_westend_tests {
 			bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 			bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
 			SIBLING_PARACHAIN_ID,
-			Rococo,
+			ByGenesis(ROCOCO_GENESIS_HASH),
 			|| {
 				// we need to create lane between sibling parachain and remote destination
 				bridge_hub_test_utils::ensure_opened_bridge::<
@@ -643,7 +643,7 @@ mod bridge_hub_bulletin_tests {
 			slot_durations(),
 			bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 			SIBLING_PEOPLE_PARACHAIN_ID,
-			Rococo,
+			ByGenesis(ROCOCO_GENESIS_HASH),
 			|| {
 				// we need to create lane between RococoPeople and RococoBulletin
 				bridge_hub_test_utils::ensure_opened_bridge::<
@@ -676,7 +676,7 @@ mod bridge_hub_bulletin_tests {
 			slot_durations(),
 			bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 			SIBLING_PEOPLE_PARACHAIN_ID,
-			Rococo,
+			ByGenesis(ROCOCO_GENESIS_HASH),
 			|| {
 				// we need to create lane between RococoPeople and RococoBulletin
 				bridge_hub_test_utils::ensure_opened_bridge::<
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs
index dbca4166a13..94921fd8af9 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs
@@ -229,3 +229,48 @@ pub mod benchmark_helpers {
 		}
 	}
 }
+
+pub(crate) mod migrations {
+	use alloc::vec::Vec;
+	use frame_support::pallet_prelude::*;
+	use snowbridge_core::TokenId;
+
+	#[frame_support::storage_alias]
+	pub type OldNativeToForeignId<T: snowbridge_pallet_system::Config> = StorageMap<
+		snowbridge_pallet_system::Pallet<T>,
+		Blake2_128Concat,
+		xcm::v4::Location,
+		TokenId,
+		OptionQuery,
+	>;
+
+	/// One shot migration for NetworkId::Westend to NetworkId::ByGenesis(WESTEND_GENESIS_HASH)
+	pub struct MigrationForXcmV5<T: snowbridge_pallet_system::Config>(core::marker::PhantomData<T>);
+	impl<T: snowbridge_pallet_system::Config> frame_support::traits::OnRuntimeUpgrade
+		for MigrationForXcmV5<T>
+	{
+		fn on_runtime_upgrade() -> Weight {
+			let mut weight = T::DbWeight::get().reads(1);
+
+			let translate_westend = |pre: xcm::v4::Location| -> Option<xcm::v5::Location> {
+				weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
+				Some(xcm::v5::Location::try_from(pre).expect("valid location"))
+			};
+			snowbridge_pallet_system::ForeignToNativeId::<T>::translate_values(translate_westend);
+
+			let old_keys = OldNativeToForeignId::<T>::iter_keys().collect::<Vec<_>>();
+			for old_key in old_keys {
+				if let Some(old_val) = OldNativeToForeignId::<T>::get(&old_key) {
+					snowbridge_pallet_system::NativeToForeignId::<T>::insert(
+						&xcm::v5::Location::try_from(old_key.clone()).expect("valid location"),
+						old_val,
+					);
+				}
+				OldNativeToForeignId::<T>::remove(old_key);
+				weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
+			}
+
+			weight
+		}
+	}
+}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs
index aca51b320e9..62c93da7c83 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs
@@ -44,7 +44,7 @@ use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSyst
 use polkadot_parachain_primitives::primitives::Sibling;
 use testnet_parachains_constants::westend::currency::UNITS as WND;
 use xcm::{
-	latest::prelude::*,
+	latest::{prelude::*, ROCOCO_GENESIS_HASH},
 	prelude::{InteriorLocation, NetworkId},
 };
 use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia};
@@ -57,7 +57,7 @@ parameter_types! {
 	pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
 
 	pub BridgeWestendToRococoMessagesPalletInstance: InteriorLocation = [PalletInstance(<BridgeRococoMessages as PalletInfoAccess>::index() as u8)].into();
-	pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo;
+	pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub RococoGlobalConsensusNetworkLocation: Location = Location::new(
 		2,
 		[GlobalConsensus(RococoGlobalConsensusNetwork::get())]
@@ -204,13 +204,15 @@ where
 {
 	use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState};
 	use sp_runtime::traits::Zero;
-	use xcm::VersionedInteriorLocation;
+	use xcm::{latest::WESTEND_GENESIS_HASH, VersionedInteriorLocation};
 
 	// insert bridge metadata
 	let lane_id = with;
 	let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]);
-	let universal_source = [GlobalConsensus(Westend), Parachain(sibling_para_id)].into();
-	let universal_destination = [GlobalConsensus(Rococo), Parachain(2075)].into();
+	let universal_source =
+		[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(sibling_para_id)].into();
+	let universal_destination =
+		[GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(2075)].into();
 	let bridge_id = BridgeId::new(&universal_source, &universal_destination);
 
 	// insert only bridge metadata, because the benchmarks create lanes
@@ -332,7 +334,6 @@ mod tests {
 pub mod migration {
 	use super::*;
 	use bp_messages::LegacyLaneId;
-	use frame_support::traits::ConstBool;
 
 	parameter_types! {
 		pub AssetHubWestendToAssetHubRococoMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]);
@@ -340,18 +341,6 @@ pub mod migration {
 		pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into();
 	}
 
-	/// Ensure that the existing lanes for the AHW<>AHR bridge are correctly configured.
-	pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane<
-		Runtime,
-		XcmOverBridgeHubRococoInstance,
-		AssetHubWestendToAssetHubRococoMessagesLane,
-		// the lanes are already created for AHR<>AHW, but we need to link them to the bridge
-		// structs
-		ConstBool<false>,
-		AssetHubWestendLocation,
-		AssetHubRococoUniversalLocation,
-	>;
-
 	mod v1_wrong {
 		use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer};
 		use bp_runtime::AccountIdOf;
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs
index e639b899149..421c3624677 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs
@@ -22,6 +22,7 @@ use parachains_common::{AccountId, AuraId};
 use sp_genesis_builder::PresetId;
 use sp_keyring::Sr25519Keyring;
 use testnet_parachains_constants::westend::xcm_version::SAFE_XCM_VERSION;
+use xcm::latest::ROCOCO_GENESIS_HASH;
 
 const BRIDGE_HUB_WESTEND_ED: Balance = ExistentialDeposit::get();
 
@@ -102,7 +103,10 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option<sp_std::vec::Vec<
 			westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(),
 			vec![(
 				Location::new(1, [Parachain(1000)]),
-				Junctions::from([Rococo.into(), Parachain(1000)]),
+				Junctions::from([
+					NetworkId::ByGenesis(ROCOCO_GENESIS_HASH).into(),
+					Parachain(1000),
+				]),
 				Some(bp_messages::LegacyLaneId([0, 0, 0, 2])),
 			)],
 		),
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
index 7c71f30b356..06540001679 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs
@@ -87,6 +87,9 @@ use pallet_bridge_messages::LaneIdOf;
 pub use sp_runtime::BuildStorage;
 
 use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
+
+#[cfg(feature = "runtime-benchmarks")]
+use xcm::latest::ROCOCO_GENESIS_HASH;
 use xcm::prelude::*;
 
 use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
@@ -152,20 +155,20 @@ pub type Migrations = (
 		Runtime,
 		bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance,
 	>,
-	bridge_to_rococo_config::migration::StaticToDynamicLanes,
 	frame_support::migrations::RemoveStorage<
 		BridgeRococoMessagesPalletName,
 		OutboundLanesCongestedSignalsKey,
 		RocksDbWeight,
 	>,
 	pallet_bridge_relayers::migration::v1::MigrationToV1<Runtime, ()>,
-	// permanent
-	pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,
 	snowbridge_pallet_system::migration::v0::InitializeOnUpgrade<
 		Runtime,
 		ConstU32<BRIDGE_HUB_ID>,
 		ConstU32<ASSET_HUB_ID>,
 	>,
+	bridge_to_ethereum_config::migrations::MigrationForXcmV5<Runtime>,
+	// permanent
+	pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,
 );
 
 parameter_types! {
@@ -1155,7 +1158,7 @@ impl_runtime_apis! {
 					);
 
 					// open bridge
-					let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(8765)].into();
+					let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(8765)].into();
 					let locations = XcmOverBridgeHubRococo::bridge_locations(
 						sibling_parachain_location.clone(),
 						bridge_destination_universal_location.clone(),
@@ -1177,7 +1180,7 @@ impl_runtime_apis! {
 					Ok(
 						(
 							sibling_parachain_location,
-							NetworkId::Rococo,
+							NetworkId::ByGenesis(ROCOCO_GENESIS_HASH),
 							[Parachain(8765)].into()
 						)
 					)
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
index 3961cc6d5cd..473807ea5eb 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
@@ -23,7 +23,10 @@ use codec::Encode;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -82,11 +85,7 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -134,12 +133,35 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubWestendXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -152,6 +174,9 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubWestendXcmWeight<Call> {
 	fn clear_error() -> Weight {
 		XcmGeneric::<Runtime>::clear_error()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 	fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight {
 		XcmGeneric::<Runtime>::claim_asset()
 	}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 5bd1d1680aa..555303d30b6 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_218_000 picoseconds.
-		Weight::from_parts(30_783_000, 3593)
+		// Minimum execution time: 31_340_000 picoseconds.
+		Weight::from_parts(32_044_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `6196`
-		// Minimum execution time: 42_631_000 picoseconds.
-		Weight::from_parts(43_127_000, 6196)
+		// Minimum execution time: 44_483_000 picoseconds.
+		Weight::from_parts(45_215_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -90,8 +90,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `260`
 		//  Estimated: `8799`
-		// Minimum execution time: 100_978_000 picoseconds.
-		Weight::from_parts(102_819_000, 8799)
+		// Minimum execution time: 106_531_000 picoseconds.
+		Weight::from_parts(109_012_000, 8799)
 			.saturating_add(T::DbWeight::get().reads(10))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
@@ -124,8 +124,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `208`
 		//  Estimated: `6196`
-		// Minimum execution time: 71_533_000 picoseconds.
-		Weight::from_parts(72_922_000, 6196)
+		// Minimum execution time: 75_043_000 picoseconds.
+		Weight::from_parts(77_425_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -133,8 +133,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_863_000 picoseconds.
-		Weight::from_parts(2_997_000, 0)
+		// Minimum execution time: 2_739_000 picoseconds.
+		Weight::from_parts(2_855_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -142,8 +142,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `52`
 		//  Estimated: `3593`
-		// Minimum execution time: 23_763_000 picoseconds.
-		Weight::from_parts(24_438_000, 3593)
+		// Minimum execution time: 25_043_000 picoseconds.
+		Weight::from_parts(25_297_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -167,8 +167,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `159`
 		//  Estimated: `6196`
-		// Minimum execution time: 78_182_000 picoseconds.
-		Weight::from_parts(79_575_000, 6196)
+		// Minimum execution time: 82_421_000 picoseconds.
+		Weight::from_parts(84_128_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -192,9 +192,34 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `107`
 		//  Estimated: `3593`
-		// Minimum execution time: 46_767_000 picoseconds.
-		Weight::from_parts(47_823_000, 3593)
+		// Minimum execution time: 52_465_000 picoseconds.
+		Weight::from_parts(53_568_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
+	// Storage: `System::Account` (r:2 w:2)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
+	// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `159`
+		//  Estimated: `6196`
+		// Minimum execution time: 87_253_000 picoseconds.
+		Weight::from_parts(88_932_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(9))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 16c483a2181..849456af925 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -68,8 +68,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `208`
 		//  Estimated: `6196`
-		// Minimum execution time: 70_715_000 picoseconds.
-		Weight::from_parts(72_211_000, 6196)
+		// Minimum execution time: 70_353_000 picoseconds.
+		Weight::from_parts(72_257_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -77,8 +77,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 968_000 picoseconds.
-		Weight::from_parts(1_022_000, 0)
+		// Minimum execution time: 996_000 picoseconds.
+		Weight::from_parts(1_027_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_926_000 picoseconds.
+		Weight::from_parts(2_033_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -86,58 +93,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 7_718_000 picoseconds.
-		Weight::from_parts(7_894_000, 3497)
+		// Minimum execution time: 7_961_000 picoseconds.
+		Weight::from_parts(8_256_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_662_000 picoseconds.
-		Weight::from_parts(7_937_000, 0)
+		// Minimum execution time: 7_589_000 picoseconds.
+		Weight::from_parts(7_867_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_699_000 picoseconds.
-		Weight::from_parts(1_783_000, 0)
+		// Minimum execution time: 1_602_000 picoseconds.
+		Weight::from_parts(1_660_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 977_000 picoseconds.
-		Weight::from_parts(1_045_000, 0)
+		// Minimum execution time: 1_056_000 picoseconds.
+		Weight::from_parts(1_096_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 971_000 picoseconds.
-		Weight::from_parts(1_030_000, 0)
+		// Minimum execution time: 1_014_000 picoseconds.
+		Weight::from_parts(1_075_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 958_000 picoseconds.
-		Weight::from_parts(996_000, 0)
+		// Minimum execution time: 986_000 picoseconds.
+		Weight::from_parts(1_031_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 992_000 picoseconds.
-		Weight::from_parts(1_056_000, 0)
+		// Minimum execution time: 1_015_000 picoseconds.
+		Weight::from_parts(1_069_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 975_000 picoseconds.
-		Weight::from_parts(1_026_000, 0)
+		// Minimum execution time: 993_000 picoseconds.
+		Weight::from_parts(1_063_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -159,8 +166,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `208`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_236_000 picoseconds.
-		Weight::from_parts(68_712_000, 6196)
+		// Minimum execution time: 66_350_000 picoseconds.
+		Weight::from_parts(68_248_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -170,8 +177,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 10_890_000 picoseconds.
-		Weight::from_parts(11_223_000, 3555)
+		// Minimum execution time: 11_247_000 picoseconds.
+		Weight::from_parts(11_468_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -179,8 +186,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 959_000 picoseconds.
-		Weight::from_parts(1_018_000, 0)
+		// Minimum execution time: 1_060_000 picoseconds.
+		Weight::from_parts(1_103_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -200,8 +207,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 25_162_000 picoseconds.
-		Weight::from_parts(25_621_000, 3503)
+		// Minimum execution time: 25_599_000 picoseconds.
+		Weight::from_parts(26_336_000, 3503)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -211,44 +218,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_949_000 picoseconds.
-		Weight::from_parts(3_119_000, 0)
+		// Minimum execution time: 2_863_000 picoseconds.
+		Weight::from_parts(3_090_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_329_000 picoseconds.
-		Weight::from_parts(1_410_000, 0)
+		// Minimum execution time: 1_385_000 picoseconds.
+		Weight::from_parts(1_468_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_063_000 picoseconds.
-		Weight::from_parts(1_101_000, 0)
+		// Minimum execution time: 1_087_000 picoseconds.
+		Weight::from_parts(1_164_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 991_000 picoseconds.
-		Weight::from_parts(1_041_000, 0)
+		// Minimum execution time: 1_022_000 picoseconds.
+		Weight::from_parts(1_066_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 944_000 picoseconds.
-		Weight::from_parts(998_000, 0)
+		// Minimum execution time: 1_015_000 picoseconds.
+		Weight::from_parts(1_070_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_100_000 picoseconds.
-		Weight::from_parts(1_180_000, 0)
+		// Minimum execution time: 1_203_000 picoseconds.
+		Weight::from_parts(1_241_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -270,8 +277,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `208`
 		//  Estimated: `6196`
-		// Minimum execution time: 71_203_000 picoseconds.
-		Weight::from_parts(73_644_000, 6196)
+		// Minimum execution time: 70_773_000 picoseconds.
+		Weight::from_parts(72_730_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -279,8 +286,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_018_000 picoseconds.
-		Weight::from_parts(4_267_000, 0)
+		// Minimum execution time: 4_173_000 picoseconds.
+		Weight::from_parts(4_445_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -302,8 +309,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `208`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_893_000 picoseconds.
-		Weight::from_parts(69_220_000, 6196)
+		// Minimum execution time: 66_471_000 picoseconds.
+		Weight::from_parts(68_362_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(9))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -311,22 +318,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 980_000 picoseconds.
-		Weight::from_parts(1_043_000, 0)
+		// Minimum execution time: 1_067_000 picoseconds.
+		Weight::from_parts(1_108_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 944_000 picoseconds.
-		Weight::from_parts(981_000, 0)
+		// Minimum execution time: 997_000 picoseconds.
+		Weight::from_parts(1_043_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 930_000 picoseconds.
-		Weight::from_parts(962_000, 0)
+		// Minimum execution time: 1_000_000 picoseconds.
+		Weight::from_parts(1_056_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -343,12 +350,12 @@ impl<T: frame_system::Config> WeightInfo<T> {
 	/// The range of component `x` is `[1, 1000]`.
 	pub fn export_message(x: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `552`
-		//  Estimated: `6492`
-		// Minimum execution time: 56_762_000 picoseconds.
-		Weight::from_parts(58_320_046, 6492)
-			// Standard Error: 162
-			.saturating_add(Weight::from_parts(51_730, 0).saturating_mul(x.into()))
+		//  Measured:  `225`
+		//  Estimated: `6165`
+		// Minimum execution time: 43_316_000 picoseconds.
+		Weight::from_parts(45_220_843, 6165)
+			// Standard Error: 169
+			.saturating_add(Weight::from_parts(44_459, 0).saturating_mul(x.into()))
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -356,14 +363,21 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 971_000 picoseconds.
-		Weight::from_parts(1_018_000, 0)
+		// Minimum execution time: 998_000 picoseconds.
+		Weight::from_parts(1_054_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 979_000 picoseconds.
-		Weight::from_parts(1_026_000, 0)
+		// Minimum execution time: 995_000 picoseconds.
+		Weight::from_parts(1_060_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs
index ae31ca4cedf..e692568932f 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs
@@ -39,7 +39,7 @@ use snowbridge_runtime_common::XcmExportFeeToSibling;
 use sp_runtime::traits::AccountIdConversion;
 use sp_std::marker::PhantomData;
 use testnet_parachains_constants::westend::snowbridge::EthereumNetwork;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -57,7 +57,7 @@ use xcm_executor::{
 
 parameter_types! {
 	pub const WestendLocation: Location = Location::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Westend;
+	pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation =
 		[GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
@@ -290,7 +290,7 @@ impl<WaivedLocations: Contains<Location>, FeeHandler: HandleFee> FeeManager
 	fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool {
 		let Some(loc) = origin else { return false };
 		if let Export { network, destination: Here } = fee_reason {
-			if network == EthereumNetwork::get() {
+			if network == EthereumNetwork::get().into() {
 				return false
 			}
 		}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs
index e5b67353c0f..69301b34fe6 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs
@@ -46,7 +46,7 @@ use sp_runtime::{
 	AccountId32, Perbill,
 };
 use testnet_parachains_constants::westend::{consensus::*, fee::WeightToFee};
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_runtime_apis::conversions::LocationToAccountHelper;
 
 // Random para id of sibling chain used in tests.
@@ -296,7 +296,7 @@ fn relayed_incoming_message_works() {
 		bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
 		bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 		SIBLING_PARACHAIN_ID,
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		|| {
 			// we need to create lane between sibling parachain and remote destination
 			bridge_hub_test_utils::ensure_opened_bridge::<
@@ -330,7 +330,7 @@ fn free_relay_extrinsic_works() {
 		bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
 		bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
 		SIBLING_PARACHAIN_ID,
-		Westend,
+		ByGenesis(WESTEND_GENESIS_HASH),
 		|| {
 			// we need to create lane between sibling parachain and remote destination
 			bridge_hub_test_utils::ensure_opened_bridge::<
diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs
index 5f91897262f..2f5aa76fbdd 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs
@@ -23,7 +23,7 @@ use frame_support::{
 use pallet_message_queue::OnQueueChanged;
 use scale_info::TypeInfo;
 use snowbridge_core::ChannelId;
-use xcm::v4::{Junction, Location};
+use xcm::latest::prelude::{Junction, Location};
 
 /// The aggregate origin of an inbound message.
 /// This is specialized for BridgeHub, as the snowbridge-outbound-queue-pallet is also using
@@ -53,7 +53,7 @@ impl From<AggregateMessageOrigin> for Location {
 			Here => Location::here(),
 			Parent => Location::parent(),
 			Sibling(id) => Location::new(1, Junction::Parachain(id.into())),
-			// NOTE: We don't need this conversion for Snowbridge. However we have to
+			// NOTE: We don't need this conversion for Snowbridge. However, we have to
 			// implement it anyway as xcm_builder::ProcessXcmMessage requires it.
 			Snowbridge(_) => Location::default(),
 		}
diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs
index 24372f57ae7..ad6db0b83e8 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs
@@ -129,11 +129,8 @@ pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
 		});
 
 		// execute XCM with Transacts to `initialize bridge` as governance does
-		assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
-			initialize_call.encode(),
-			initialize_call.get_dispatch_info().call_weight,
-		)
-		.ensure_complete());
+		assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(initialize_call.encode(),)
+			.ensure_complete());
 
 		// check mode after
 		assert_eq!(
@@ -172,7 +169,6 @@ pub fn change_bridge_grandpa_pallet_mode_by_governance_works<Runtime, GrandpaPal
 			// execute XCM with Transacts to `initialize bridge` as governance does
 			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
 				set_operating_mode_call.encode(),
-				set_operating_mode_call.get_dispatch_info().call_weight,
 			)
 			.ensure_complete());
 
@@ -225,7 +221,6 @@ pub fn change_bridge_parachains_pallet_mode_by_governance_works<Runtime, Paracha
 			// execute XCM with Transacts to `initialize bridge` as governance does
 			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
 				set_operating_mode_call.encode(),
-				set_operating_mode_call.get_dispatch_info().call_weight,
 			)
 			.ensure_complete());
 
@@ -278,7 +273,6 @@ pub fn change_bridge_messages_pallet_mode_by_governance_works<Runtime, MessagesP
 			// execute XCM with Transacts to `initialize bridge` as governance does
 			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
 				set_operating_mode_call.encode(),
-				set_operating_mode_call.get_dispatch_info().call_weight,
 			)
 			.ensure_complete());
 
diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs
index f8e03303c32..56ef2e8ba02 100644
--- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs
@@ -33,7 +33,7 @@ use parachains_common::xcm_config::{
 use polkadot_parachain_primitives::primitives::Sibling;
 use polkadot_runtime_common::xcm_sender::ExponentialPrice;
 use westend_runtime_constants::xcm as xcm_constants;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -50,7 +50,7 @@ use xcm_executor::XcmExecutor;
 parameter_types! {
 	pub const RootLocation: Location = Location::here();
 	pub const WndLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Westend);
+	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();
diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs
index 39fdd30a049..0151837aa35 100644
--- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs
@@ -36,7 +36,7 @@ use polkadot_parachain_primitives::primitives::Sibling;
 use polkadot_runtime_common::xcm_sender::ExponentialPrice;
 use sp_runtime::traits::AccountIdConversion;
 use testnet_parachains_constants::rococo::currency::CENTS;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -52,7 +52,7 @@ use xcm_executor::XcmExecutor;
 
 parameter_types! {
 	pub const RelayLocation: Location = Location::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Rococo;
+	pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
 	pub const ExecutiveBody: BodyId = BodyId::Executive;
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
index 3910a747e9b..d76ac443a14 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs
@@ -134,7 +134,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1000000000, 200000),
 				call: request_core_count_call.encode().into(),
 			},
 		]);
@@ -164,7 +163,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1000000000, 200000),
 				call: request_revenue_info_at_call.encode().into(),
 			},
 		]);
@@ -193,7 +191,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1000000000, 200000),
 				call: credit_account_call.encode().into(),
 			},
 		]);
@@ -258,7 +255,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1_000_000_000, 200000),
 				call: assign_core_call.encode().into(),
 			},
 		]);
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
index b8db473f106..48f1366e2c5 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
@@ -22,7 +22,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -81,11 +84,7 @@ impl<Call> XcmWeightInfo<Call> for CoretimeRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -132,12 +131,35 @@ impl<Call> XcmWeightInfo<Call> for CoretimeRococoXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -229,4 +251,7 @@ impl<Call> XcmWeightInfo<Call> for CoretimeRococoXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index c8dbdadf7b1..0a2d74de0cb 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 29_812_000 picoseconds.
-		Weight::from_parts(30_526_000, 3593)
+		// Minimum execution time: 31_260_000 picoseconds.
+		Weight::from_parts(31_771_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 39_430_000 picoseconds.
-		Weight::from_parts(39_968_000, 6196)
+		// Minimum execution time: 42_231_000 picoseconds.
+		Weight::from_parts(42_718_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -88,8 +88,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `207`
 		//  Estimated: `6196`
-		// Minimum execution time: 65_555_000 picoseconds.
-		Weight::from_parts(67_161_000, 6196)
+		// Minimum execution time: 68_764_000 picoseconds.
+		Weight::from_parts(70_505_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -118,8 +118,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 30_491_000 picoseconds.
-		Weight::from_parts(31_991_000, 3571)
+		// Minimum execution time: 31_390_000 picoseconds.
+		Weight::from_parts(32_057_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -127,8 +127,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_568_000 picoseconds.
-		Weight::from_parts(2_703_000, 0)
+		// Minimum execution time: 2_288_000 picoseconds.
+		Weight::from_parts(2_477_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -136,8 +136,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 22_159_000 picoseconds.
-		Weight::from_parts(22_517_000, 3593)
+		// Minimum execution time: 22_946_000 picoseconds.
+		Weight::from_parts(23_462_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +159,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3593`
-		// Minimum execution time: 57_126_000 picoseconds.
-		Weight::from_parts(58_830_000, 3593)
+		// Minimum execution time: 59_017_000 picoseconds.
+		Weight::from_parts(60_338_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -180,9 +180,32 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 26_589_000 picoseconds.
-		Weight::from_parts(27_285_000, 3571)
+		// Minimum execution time: 29_953_000 picoseconds.
+		Weight::from_parts(30_704_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	// Storage: `System::Account` (r:1 w:1)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `106`
+		//  Estimated: `3593`
+		// Minimum execution time: 65_118_000 picoseconds.
+		Weight::from_parts(66_096_000, 3593)
+			.saturating_add(T::DbWeight::get().reads(7))
+			.saturating_add(T::DbWeight::get().writes(3))
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 676048f92ad..229dafb7c5e 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 23_760_000 picoseconds.
-		Weight::from_parts(24_411_000, 3571)
+		// Minimum execution time: 29_263_000 picoseconds.
+		Weight::from_parts(30_387_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -73,8 +73,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 522_000 picoseconds.
-		Weight::from_parts(546_000, 0)
+		// Minimum execution time: 603_000 picoseconds.
+		Weight::from_parts(664_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_530_000 picoseconds.
+		Weight::from_parts(1_662_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -82,58 +89,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 5_830_000 picoseconds.
-		Weight::from_parts(6_069_000, 3497)
+		// Minimum execution time: 7_290_000 picoseconds.
+		Weight::from_parts(7_493_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_508_000 picoseconds.
-		Weight::from_parts(5_801_000, 0)
+		// Minimum execution time: 6_785_000 picoseconds.
+		Weight::from_parts(7_012_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_130_000 picoseconds.
-		Weight::from_parts(1_239_000, 0)
+		// Minimum execution time: 1_299_000 picoseconds.
+		Weight::from_parts(1_380_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 541_000 picoseconds.
-		Weight::from_parts(567_000, 0)
+		// Minimum execution time: 655_000 picoseconds.
+		Weight::from_parts(681_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 560_000 picoseconds.
-		Weight::from_parts(591_000, 0)
+		// Minimum execution time: 625_000 picoseconds.
+		Weight::from_parts(669_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 505_000 picoseconds.
-		Weight::from_parts(547_000, 0)
+		// Minimum execution time: 607_000 picoseconds.
+		Weight::from_parts(650_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 538_000 picoseconds.
-		Weight::from_parts(565_000, 0)
+		// Minimum execution time: 655_000 picoseconds.
+		Weight::from_parts(688_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 514_000 picoseconds.
-		Weight::from_parts(541_000, 0)
+		// Minimum execution time: 602_000 picoseconds.
+		Weight::from_parts(650_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -151,8 +158,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 20_920_000 picoseconds.
-		Weight::from_parts(21_437_000, 3571)
+		// Minimum execution time: 26_176_000 picoseconds.
+		Weight::from_parts(26_870_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -162,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 8_549_000 picoseconds.
-		Weight::from_parts(8_821_000, 3555)
+		// Minimum execution time: 10_674_000 picoseconds.
+		Weight::from_parts(10_918_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -171,8 +178,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 525_000 picoseconds.
-		Weight::from_parts(544_000, 0)
+		// Minimum execution time: 601_000 picoseconds.
+		Weight::from_parts(639_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -190,8 +197,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 19_645_000 picoseconds.
-		Weight::from_parts(20_104_000, 3539)
+		// Minimum execution time: 24_220_000 picoseconds.
+		Weight::from_parts(24_910_000, 3539)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -201,44 +208,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_232_000 picoseconds.
-		Weight::from_parts(2_334_000, 0)
+		// Minimum execution time: 2_464_000 picoseconds.
+		Weight::from_parts(2_618_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 883_000 picoseconds.
-		Weight::from_parts(945_000, 0)
+		// Minimum execution time: 984_000 picoseconds.
+		Weight::from_parts(1_041_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 600_000 picoseconds.
-		Weight::from_parts(645_000, 0)
+		// Minimum execution time: 730_000 picoseconds.
+		Weight::from_parts(769_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 527_000 picoseconds.
-		Weight::from_parts(552_000, 0)
+		// Minimum execution time: 615_000 picoseconds.
+		Weight::from_parts(658_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 527_000 picoseconds.
-		Weight::from_parts(550_000, 0)
+		// Minimum execution time: 607_000 picoseconds.
+		Weight::from_parts(637_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 657_000 picoseconds.
-		Weight::from_parts(703_000, 0)
+		// Minimum execution time: 791_000 picoseconds.
+		Weight::from_parts(838_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -256,8 +263,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 24_999_000 picoseconds.
-		Weight::from_parts(25_671_000, 3571)
+		// Minimum execution time: 30_210_000 picoseconds.
+		Weight::from_parts(30_973_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -265,8 +272,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_159_000 picoseconds.
-		Weight::from_parts(3_296_000, 0)
+		// Minimum execution time: 3_097_000 picoseconds.
+		Weight::from_parts(3_277_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -284,8 +291,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 21_052_000 picoseconds.
-		Weight::from_parts(22_153_000, 3571)
+		// Minimum execution time: 26_487_000 picoseconds.
+		Weight::from_parts(27_445_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -293,35 +300,42 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 547_000 picoseconds.
-		Weight::from_parts(584_000, 0)
+		// Minimum execution time: 655_000 picoseconds.
+		Weight::from_parts(689_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 506_000 picoseconds.
-		Weight::from_parts(551_000, 0)
+		// Minimum execution time: 627_000 picoseconds.
+		Weight::from_parts(659_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 508_000 picoseconds.
-		Weight::from_parts(527_000, 0)
+		// Minimum execution time: 603_000 picoseconds.
+		Weight::from_parts(650_000, 0)
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 527_000 picoseconds.
-		Weight::from_parts(558_000, 0)
+		// Minimum execution time: 594_000 picoseconds.
+		Weight::from_parts(645_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 514_000 picoseconds.
-		Weight::from_parts(553_000, 0)
+		// Minimum execution time: 650_000 picoseconds.
+		Weight::from_parts(673_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs
index 2eae13de2fd..37bf1e68144 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs
@@ -37,7 +37,7 @@ use parachains_common::{
 use polkadot_parachain_primitives::primitives::Sibling;
 use polkadot_runtime_common::xcm_sender::ExponentialPrice;
 use sp_runtime::traits::AccountIdConversion;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -53,7 +53,7 @@ use xcm_executor::XcmExecutor;
 
 parameter_types! {
 	pub const RocRelayLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Rococo);
+	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH));
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation =
 		[GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into();
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
index 86769cb2da1..f0c03849750 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs
@@ -127,12 +127,6 @@ impl CoretimeInterface for CoretimeAllocator {
 		use crate::coretime::CoretimeProviderCalls::RequestCoreCount;
 		let request_core_count_call = RelayRuntimePallets::Coretime(RequestCoreCount(count));
 
-		// Weight for `request_core_count` from westend benchmarks:
-		// `ref_time` = 7889000 + (3 * 25000000) + (1 * 100000000) = 182889000
-		// `proof_size` = 1636
-		// Add 5% to each component and round to 2 significant figures.
-		let call_weight = Weight::from_parts(190_000_000, 1700);
-
 		let message = Xcm(vec![
 			Instruction::UnpaidExecution {
 				weight_limit: WeightLimit::Unlimited,
@@ -140,7 +134,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: call_weight,
 				call: request_core_count_call.encode().into(),
 			},
 		]);
@@ -170,7 +163,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1000000000, 200000),
 				call: request_revenue_info_at_call.encode().into(),
 			},
 		]);
@@ -199,7 +191,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: Weight::from_parts(1000000000, 200000),
 				call: credit_account_call.encode().into(),
 			},
 		]);
@@ -225,12 +216,6 @@ impl CoretimeInterface for CoretimeAllocator {
 	) {
 		use crate::coretime::CoretimeProviderCalls::AssignCore;
 
-		// Weight for `assign_core` from westend benchmarks:
-		// `ref_time` = 10177115 + (1 * 25000000) + (2 * 100000000) + (57600 * 13932) = 937660315
-		// `proof_size` = 3612
-		// Add 5% to each component and round to 2 significant figures.
-		let call_weight = Weight::from_parts(980_000_000, 3800);
-
 		// The relay chain currently only allows `assign_core` to be called with a complete mask
 		// and only ever with increasing `begin`. The assignments must be truncated to avoid
 		// dropping that core's assignment completely.
@@ -270,7 +255,6 @@ impl CoretimeInterface for CoretimeAllocator {
 			},
 			Instruction::Transact {
 				origin_kind: OriginKind::Native,
-				require_weight_at_most: call_weight,
 				call: assign_core_call.encode().into(),
 			},
 		]);
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
index f35f7bfc188..1f4b4aa5c5a 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
@@ -21,7 +21,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -80,11 +83,7 @@ impl<Call> XcmWeightInfo<Call> for CoretimeWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -132,12 +131,35 @@ impl<Call> XcmWeightInfo<Call> for CoretimeWestendXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -150,6 +172,9 @@ impl<Call> XcmWeightInfo<Call> for CoretimeWestendXcmWeight<Call> {
 	fn clear_error() -> Weight {
 		XcmGeneric::<Runtime>::clear_error()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 	fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight {
 		XcmGeneric::<Runtime>::claim_asset()
 	}
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 935636651eb..227f3617da0 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 29_866_000 picoseconds.
-		Weight::from_parts(30_363_000, 3593)
+		// Minimum execution time: 30_623_000 picoseconds.
+		Weight::from_parts(31_009_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 39_434_000 picoseconds.
-		Weight::from_parts(40_274_000, 6196)
+		// Minimum execution time: 40_553_000 picoseconds.
+		Weight::from_parts(41_309_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -88,8 +88,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `207`
 		//  Estimated: `6196`
-		// Minimum execution time: 66_303_000 picoseconds.
-		Weight::from_parts(68_294_000, 6196)
+		// Minimum execution time: 66_837_000 picoseconds.
+		Weight::from_parts(68_463_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -118,8 +118,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 30_523_000 picoseconds.
-		Weight::from_parts(31_289_000, 3571)
+		// Minimum execution time: 30_020_000 picoseconds.
+		Weight::from_parts(31_409_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -127,8 +127,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_517_000 picoseconds.
-		Weight::from_parts(2_634_000, 0)
+		// Minimum execution time: 2_355_000 picoseconds.
+		Weight::from_parts(2_464_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -136,8 +136,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 22_151_000 picoseconds.
-		Weight::from_parts(22_907_000, 3593)
+		// Minimum execution time: 22_702_000 picoseconds.
+		Weight::from_parts(23_422_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +159,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3593`
-		// Minimum execution time: 57_763_000 picoseconds.
-		Weight::from_parts(58_941_000, 3593)
+		// Minimum execution time: 58_610_000 picoseconds.
+		Weight::from_parts(59_659_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -180,9 +180,32 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 26_322_000 picoseconds.
-		Weight::from_parts(27_197_000, 3571)
+		// Minimum execution time: 29_178_000 picoseconds.
+		Weight::from_parts(29_860_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	// Storage: `System::Account` (r:1 w:1)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `106`
+		//  Estimated: `3593`
+		// Minimum execution time: 63_658_000 picoseconds.
+		Weight::from_parts(64_869_000, 3593)
+			.saturating_add(T::DbWeight::get().reads(7))
+			.saturating_add(T::DbWeight::get().writes(3))
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 7390f35e397..bd70bc4f4bd 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 23_688_000 picoseconds.
-		Weight::from_parts(24_845_000, 3571)
+		// Minimum execution time: 29_463_000 picoseconds.
+		Weight::from_parts(30_178_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -73,8 +73,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 569_000 picoseconds.
-		Weight::from_parts(619_000, 0)
+		// Minimum execution time: 568_000 picoseconds.
+		Weight::from_parts(608_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_530_000 picoseconds.
+		Weight::from_parts(1_585_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -82,58 +89,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 5_851_000 picoseconds.
-		Weight::from_parts(6_061_000, 3497)
+		// Minimum execution time: 7_400_000 picoseconds.
+		Weight::from_parts(7_572_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 5_770_000 picoseconds.
-		Weight::from_parts(5_916_000, 0)
+		// Minimum execution time: 6_951_000 picoseconds.
+		Weight::from_parts(7_173_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_155_000 picoseconds.
-		Weight::from_parts(1_270_000, 0)
+		// Minimum execution time: 1_245_000 picoseconds.
+		Weight::from_parts(1_342_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 558_000 picoseconds.
-		Weight::from_parts(628_000, 0)
+		// Minimum execution time: 613_000 picoseconds.
+		Weight::from_parts(657_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 603_000 picoseconds.
-		Weight::from_parts(630_000, 0)
+		// Minimum execution time: 613_000 picoseconds.
+		Weight::from_parts(656_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 533_000 picoseconds.
-		Weight::from_parts(563_000, 0)
+		// Minimum execution time: 570_000 picoseconds.
+		Weight::from_parts(608_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 597_000 picoseconds.
-		Weight::from_parts(644_000, 0)
+		// Minimum execution time: 557_000 picoseconds.
+		Weight::from_parts(607_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 536_000 picoseconds.
-		Weight::from_parts(588_000, 0)
+		// Minimum execution time: 557_000 picoseconds.
+		Weight::from_parts(578_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -151,8 +158,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 21_146_000 picoseconds.
-		Weight::from_parts(21_771_000, 3571)
+		// Minimum execution time: 26_179_000 picoseconds.
+		Weight::from_parts(27_089_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -162,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 8_446_000 picoseconds.
-		Weight::from_parts(8_660_000, 3555)
+		// Minimum execution time: 10_724_000 picoseconds.
+		Weight::from_parts(10_896_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -171,8 +178,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 561_000 picoseconds.
-		Weight::from_parts(594_000, 0)
+		// Minimum execution time: 567_000 picoseconds.
+		Weight::from_parts(623_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -190,8 +197,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `74`
 		//  Estimated: `3539`
-		// Minimum execution time: 19_953_000 picoseconds.
-		Weight::from_parts(20_608_000, 3539)
+		// Minimum execution time: 24_367_000 picoseconds.
+		Weight::from_parts(25_072_000, 3539)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -201,44 +208,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_290_000 picoseconds.
-		Weight::from_parts(2_370_000, 0)
+		// Minimum execution time: 2_554_000 picoseconds.
+		Weight::from_parts(2_757_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 943_000 picoseconds.
-		Weight::from_parts(987_000, 0)
+		// Minimum execution time: 922_000 picoseconds.
+		Weight::from_parts(992_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 635_000 picoseconds.
-		Weight::from_parts(699_000, 0)
+		// Minimum execution time: 688_000 picoseconds.
+		Weight::from_parts(723_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 553_000 picoseconds.
-		Weight::from_parts(609_000, 0)
+		// Minimum execution time: 607_000 picoseconds.
+		Weight::from_parts(647_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 547_000 picoseconds.
-		Weight::from_parts(581_000, 0)
+		// Minimum execution time: 591_000 picoseconds.
+		Weight::from_parts(620_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 700_000 picoseconds.
-		Weight::from_parts(757_000, 0)
+		// Minimum execution time: 735_000 picoseconds.
+		Weight::from_parts(802_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -256,8 +263,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 24_953_000 picoseconds.
-		Weight::from_parts(25_516_000, 3571)
+		// Minimum execution time: 29_923_000 picoseconds.
+		Weight::from_parts(30_770_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -265,8 +272,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_746_000 picoseconds.
-		Weight::from_parts(2_944_000, 0)
+		// Minimum execution time: 2_884_000 picoseconds.
+		Weight::from_parts(3_088_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -284,8 +291,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `106`
 		//  Estimated: `3571`
-		// Minimum execution time: 21_325_000 picoseconds.
-		Weight::from_parts(21_942_000, 3571)
+		// Minimum execution time: 26_632_000 picoseconds.
+		Weight::from_parts(27_228_000, 3571)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -293,35 +300,42 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 600_000 picoseconds.
-		Weight::from_parts(631_000, 0)
+		// Minimum execution time: 599_000 picoseconds.
+		Weight::from_parts(655_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 534_000 picoseconds.
-		Weight::from_parts(566_000, 0)
+		// Minimum execution time: 587_000 picoseconds.
+		Weight::from_parts(628_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 540_000 picoseconds.
-		Weight::from_parts(565_000, 0)
+		// Minimum execution time: 572_000 picoseconds.
+		Weight::from_parts(631_000, 0)
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 542_000 picoseconds.
-		Weight::from_parts(581_000, 0)
+		// Minimum execution time: 570_000 picoseconds.
+		Weight::from_parts(615_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 568_000 picoseconds.
-		Weight::from_parts(597_000, 0)
+		// Minimum execution time: 624_000 picoseconds.
+		Weight::from_parts(659_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs
index 1205be95c93..5616c585a13 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs
@@ -37,7 +37,7 @@ use parachains_common::{
 use polkadot_parachain_primitives::primitives::Sibling;
 use polkadot_runtime_common::xcm_sender::ExponentialPrice;
 use sp_runtime::traits::AccountIdConversion;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -53,7 +53,7 @@ use xcm_executor::XcmExecutor;
 
 parameter_types! {
 	pub const TokenRelayLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Westend);
+	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();
diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs
index d1fb50c1ab0..b67c32495d6 100644
--- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs
@@ -22,7 +22,7 @@ use frame_support::{
 	traits::{Contains, Everything, Nothing},
 	weights::Weight,
 };
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, FrameTransactionalProcessor,
 	ParentAsSuperuser, ParentIsPreset, SovereignSignedViaLocation,
@@ -30,7 +30,7 @@ use xcm_builder::{
 
 parameter_types! {
 	pub const WestendLocation: Location = Location::parent();
-	pub const WestendNetwork: NetworkId = NetworkId::Westend;
+	pub const WestendNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
 	pub UniversalLocation: InteriorLocation = [GlobalConsensus(WestendNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
 }
 
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
index 58007173ae1..b82872a1cbf 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
@@ -21,7 +21,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -80,11 +83,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleRococoXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -131,12 +130,35 @@ impl<Call> XcmWeightInfo<Call> for PeopleRococoXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -228,4 +250,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleRococoXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 4dd44e66dd5..f594c45e1cf 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_428_000 picoseconds.
-		Weight::from_parts(31_184_000, 3593)
+		// Minimum execution time: 30_760_000 picoseconds.
+		Weight::from_parts(31_209_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `6196`
-		// Minimum execution time: 41_912_000 picoseconds.
-		Weight::from_parts(43_346_000, 6196)
+		// Minimum execution time: 43_379_000 picoseconds.
+		Weight::from_parts(44_202_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -88,8 +88,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `223`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_706_000 picoseconds.
-		Weight::from_parts(69_671_000, 6196)
+		// Minimum execution time: 67_467_000 picoseconds.
+		Weight::from_parts(69_235_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -118,8 +118,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 29_790_000 picoseconds.
-		Weight::from_parts(30_655_000, 3535)
+		// Minimum execution time: 29_243_000 picoseconds.
+		Weight::from_parts(30_176_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -127,8 +127,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_438_000 picoseconds.
-		Weight::from_parts(2_597_000, 0)
+		// Minimum execution time: 2_294_000 picoseconds.
+		Weight::from_parts(2_424_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -136,8 +136,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `52`
 		//  Estimated: `3593`
-		// Minimum execution time: 24_040_000 picoseconds.
-		Weight::from_parts(24_538_000, 3593)
+		// Minimum execution time: 24_058_000 picoseconds.
+		Weight::from_parts(24_588_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +159,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `122`
 		//  Estimated: `3593`
-		// Minimum execution time: 58_275_000 picoseconds.
-		Weight::from_parts(59_899_000, 3593)
+		// Minimum execution time: 59_164_000 picoseconds.
+		Weight::from_parts(60_431_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -180,9 +180,32 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 25_638_000 picoseconds.
-		Weight::from_parts(26_514_000, 3535)
+		// Minimum execution time: 28_379_000 picoseconds.
+		Weight::from_parts(29_153_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	// Storage: `System::Account` (r:1 w:1)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `122`
+		//  Estimated: `3593`
+		// Minimum execution time: 64_505_000 picoseconds.
+		Weight::from_parts(66_587_000, 3593)
+			.saturating_add(T::DbWeight::get().reads(7))
+			.saturating_add(T::DbWeight::get().writes(3))
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 729a3211704..30e28fac7e5 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 29_430_000 picoseconds.
-		Weight::from_parts(30_111_000, 3535)
+		// Minimum execution time: 28_898_000 picoseconds.
+		Weight::from_parts(29_717_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -73,8 +73,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 607_000 picoseconds.
-		Weight::from_parts(672_000, 0)
+		// Minimum execution time: 690_000 picoseconds.
+		Weight::from_parts(759_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_695_000 picoseconds.
+		Weight::from_parts(1_799_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -82,58 +89,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 7_445_000 picoseconds.
-		Weight::from_parts(7_623_000, 3497)
+		// Minimum execution time: 7_441_000 picoseconds.
+		Weight::from_parts(7_746_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_749_000 picoseconds.
-		Weight::from_parts(7_073_000, 0)
+		// Minimum execution time: 6_881_000 picoseconds.
+		Weight::from_parts(7_219_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_275_000 picoseconds.
-		Weight::from_parts(1_409_000, 0)
+		// Minimum execution time: 1_390_000 picoseconds.
+		Weight::from_parts(1_471_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 670_000 picoseconds.
-		Weight::from_parts(709_000, 0)
+		// Minimum execution time: 698_000 picoseconds.
+		Weight::from_parts(743_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 635_000 picoseconds.
-		Weight::from_parts(723_000, 0)
+		// Minimum execution time: 695_000 picoseconds.
+		Weight::from_parts(746_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 650_000 picoseconds.
+		// Minimum execution time: 664_000 picoseconds.
 		Weight::from_parts(699_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 678_000 picoseconds.
-		Weight::from_parts(728_000, 0)
+		// Minimum execution time: 698_000 picoseconds.
+		Weight::from_parts(748_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 657_000 picoseconds.
-		Weight::from_parts(703_000, 0)
+		// Minimum execution time: 669_000 picoseconds.
+		Weight::from_parts(726_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -151,8 +158,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 25_795_000 picoseconds.
-		Weight::from_parts(26_415_000, 3535)
+		// Minimum execution time: 25_991_000 picoseconds.
+		Weight::from_parts(26_602_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -162,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 10_792_000 picoseconds.
-		Weight::from_parts(11_061_000, 3555)
+		// Minimum execution time: 10_561_000 picoseconds.
+		Weight::from_parts(10_913_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -171,8 +178,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 624_000 picoseconds.
-		Weight::from_parts(682_000, 0)
+		// Minimum execution time: 654_000 picoseconds.
+		Weight::from_parts(707_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -190,8 +197,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 23_906_000 picoseconds.
-		Weight::from_parts(24_740_000, 3503)
+		// Minimum execution time: 23_813_000 picoseconds.
+		Weight::from_parts(24_352_000, 3503)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -201,44 +208,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_621_000 picoseconds.
-		Weight::from_parts(2_788_000, 0)
+		// Minimum execution time: 2_499_000 picoseconds.
+		Weight::from_parts(2_655_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 954_000 picoseconds.
-		Weight::from_parts(1_046_000, 0)
+		// Minimum execution time: 1_065_000 picoseconds.
+		Weight::from_parts(1_108_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 742_000 picoseconds.
-		Weight::from_parts(790_000, 0)
+		// Minimum execution time: 747_000 picoseconds.
+		Weight::from_parts(807_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 664_000 picoseconds.
-		Weight::from_parts(722_000, 0)
+		// Minimum execution time: 685_000 picoseconds.
+		Weight::from_parts(750_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 619_000 picoseconds.
-		Weight::from_parts(672_000, 0)
+		// Minimum execution time: 664_000 picoseconds.
+		Weight::from_parts(711_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 798_000 picoseconds.
-		Weight::from_parts(851_000, 0)
+		// Minimum execution time: 830_000 picoseconds.
+		Weight::from_parts(880_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -256,8 +263,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 29_580_000 picoseconds.
-		Weight::from_parts(31_100_000, 3535)
+		// Minimum execution time: 30_051_000 picoseconds.
+		Weight::from_parts(30_720_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -265,8 +272,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_150_000 picoseconds.
-		Weight::from_parts(3_326_000, 0)
+		// Minimum execution time: 3_136_000 picoseconds.
+		Weight::from_parts(3_265_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -284,8 +291,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 26_152_000 picoseconds.
-		Weight::from_parts(26_635_000, 3535)
+		// Minimum execution time: 25_980_000 picoseconds.
+		Weight::from_parts(26_868_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -293,35 +300,42 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 693_000 picoseconds.
-		Weight::from_parts(724_000, 0)
+		// Minimum execution time: 708_000 picoseconds.
+		Weight::from_parts(755_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 632_000 picoseconds.
-		Weight::from_parts(678_000, 0)
+		// Minimum execution time: 667_000 picoseconds.
+		Weight::from_parts(702_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 646_000 picoseconds.
-		Weight::from_parts(694_000, 0)
+		// Minimum execution time: 660_000 picoseconds.
+		Weight::from_parts(695_000, 0)
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 622_000 picoseconds.
-		Weight::from_parts(656_000, 0)
+		// Minimum execution time: 669_000 picoseconds.
+		Weight::from_parts(707_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 639_000 picoseconds.
-		Weight::from_parts(679_000, 0)
+		// Minimum execution time: 685_000 picoseconds.
+		Weight::from_parts(757_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs
index a2e20e2778b..724d87587c6 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs
@@ -34,7 +34,7 @@ use parachains_common::{
 };
 use polkadot_parachain_primitives::primitives::Sibling;
 use sp_runtime::traits::AccountIdConversion;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor;
 parameter_types! {
 	pub const RootLocation: Location = Location::here();
 	pub const RelayLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Rococo);
+	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH));
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation =
 		[GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into();
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
index b44e8d4b61b..8ca9771dca4 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
@@ -21,7 +21,10 @@ use alloc::vec::Vec;
 use frame_support::weights::Weight;
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
-use xcm::{latest::prelude::*, DoubleEncoded};
+use xcm::{
+	latest::{prelude::*, AssetTransferFilter},
+	DoubleEncoded,
+};
 
 trait WeighAssets {
 	fn weigh_assets(&self, weight: Weight) -> Weight;
@@ -80,11 +83,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleWestendXcmWeight<Call> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_type: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<Call>,
-	) -> Weight {
+	fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded<Call>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -131,12 +130,35 @@ impl<Call> XcmWeightInfo<Call> for PeopleWestendXcmWeight<Call> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmFungibleWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -228,4 +250,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleWestendXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 8f6bfde986b..c12da204f35 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -54,8 +54,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_040_000 picoseconds.
-		Weight::from_parts(30_758_000, 3593)
+		// Minimum execution time: 30_401_000 picoseconds.
+		Weight::from_parts(30_813_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -65,8 +65,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `6196`
-		// Minimum execution time: 42_135_000 picoseconds.
-		Weight::from_parts(42_970_000, 6196)
+		// Minimum execution time: 43_150_000 picoseconds.
+		Weight::from_parts(43_919_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -88,8 +88,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `223`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_385_000 picoseconds.
-		Weight::from_parts(69_776_000, 6196)
+		// Minimum execution time: 67_808_000 picoseconds.
+		Weight::from_parts(69_114_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(8))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -118,8 +118,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 29_804_000 picoseconds.
-		Weight::from_parts(30_662_000, 3535)
+		// Minimum execution time: 29_312_000 picoseconds.
+		Weight::from_parts(30_347_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -127,8 +127,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_358_000 picoseconds.
-		Weight::from_parts(2_497_000, 0)
+		// Minimum execution time: 2_283_000 picoseconds.
+		Weight::from_parts(2_448_000, 0)
 	}
 	// Storage: `System::Account` (r:1 w:1)
 	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
@@ -136,8 +136,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `52`
 		//  Estimated: `3593`
-		// Minimum execution time: 23_732_000 picoseconds.
-		Weight::from_parts(24_098_000, 3593)
+		// Minimum execution time: 23_556_000 picoseconds.
+		Weight::from_parts(24_419_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -159,8 +159,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `122`
 		//  Estimated: `3593`
-		// Minimum execution time: 58_449_000 picoseconds.
-		Weight::from_parts(60_235_000, 3593)
+		// Minimum execution time: 58_342_000 picoseconds.
+		Weight::from_parts(59_598_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -180,9 +180,32 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 25_708_000 picoseconds.
-		Weight::from_parts(26_495_000, 3535)
+		// Minimum execution time: 28_285_000 picoseconds.
+		Weight::from_parts(29_016_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
+	// Storage: `System::Account` (r:1 w:1)
+	// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
+	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
+	// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
+	// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
+	// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
+	// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
+	// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	pub fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `122`
+		//  Estimated: `3593`
+		// Minimum execution time: 65_211_000 picoseconds.
+		Weight::from_parts(67_200_000, 3593)
+			.saturating_add(T::DbWeight::get().reads(7))
+			.saturating_add(T::DbWeight::get().writes(3))
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 1377d31f2db..3c539902abc 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -64,8 +64,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 29_537_000 picoseconds.
-		Weight::from_parts(30_513_000, 3535)
+		// Minimum execution time: 29_015_000 picoseconds.
+		Weight::from_parts(30_359_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -73,8 +73,15 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 683_000 picoseconds.
-		Weight::from_parts(738_000, 0)
+		// Minimum execution time: 572_000 picoseconds.
+		Weight::from_parts(637_000, 0)
+	}
+	pub fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_550_000 picoseconds.
+		Weight::from_parts(1_604_000, 0)
 	}
 	// Storage: `PolkadotXcm::Queries` (r:1 w:0)
 	// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -82,58 +89,58 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `32`
 		//  Estimated: `3497`
-		// Minimum execution time: 7_498_000 picoseconds.
-		Weight::from_parts(7_904_000, 3497)
+		// Minimum execution time: 7_354_000 picoseconds.
+		Weight::from_parts(7_808_000, 3497)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_029_000 picoseconds.
-		Weight::from_parts(7_325_000, 0)
+		// Minimum execution time: 6_716_000 picoseconds.
+		Weight::from_parts(7_067_000, 0)
 	}
 	pub fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_343_000 picoseconds.
-		Weight::from_parts(1_410_000, 0)
+		// Minimum execution time: 1_280_000 picoseconds.
+		Weight::from_parts(1_355_000, 0)
 	}
 	pub fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 696_000 picoseconds.
-		Weight::from_parts(734_000, 0)
+		// Minimum execution time: 587_000 picoseconds.
+		Weight::from_parts(645_000, 0)
 	}
 	pub fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 690_000 picoseconds.
-		Weight::from_parts(740_000, 0)
+		// Minimum execution time: 629_000 picoseconds.
+		Weight::from_parts(662_000, 0)
 	}
 	pub fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 667_000 picoseconds.
-		Weight::from_parts(697_000, 0)
+		// Minimum execution time: 590_000 picoseconds.
+		Weight::from_parts(639_000, 0)
 	}
 	pub fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 692_000 picoseconds.
-		Weight::from_parts(743_000, 0)
+		// Minimum execution time: 651_000 picoseconds.
+		Weight::from_parts(688_000, 0)
 	}
 	pub fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 670_000 picoseconds.
-		Weight::from_parts(712_000, 0)
+		// Minimum execution time: 601_000 picoseconds.
+		Weight::from_parts(630_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -151,8 +158,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 26_405_000 picoseconds.
-		Weight::from_parts(26_877_000, 3535)
+		// Minimum execution time: 25_650_000 picoseconds.
+		Weight::from_parts(26_440_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -162,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `90`
 		//  Estimated: `3555`
-		// Minimum execution time: 10_953_000 picoseconds.
-		Weight::from_parts(11_345_000, 3555)
+		// Minimum execution time: 10_492_000 picoseconds.
+		Weight::from_parts(10_875_000, 3555)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -171,8 +178,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 644_000 picoseconds.
-		Weight::from_parts(693_000, 0)
+		// Minimum execution time: 597_000 picoseconds.
+		Weight::from_parts(647_000, 0)
 	}
 	// Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1)
 	// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -190,8 +197,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `38`
 		//  Estimated: `3503`
-		// Minimum execution time: 24_157_000 picoseconds.
-		Weight::from_parts(24_980_000, 3503)
+		// Minimum execution time: 23_732_000 picoseconds.
+		Weight::from_parts(24_290_000, 3503)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -201,44 +208,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_767_000 picoseconds.
-		Weight::from_parts(2_844_000, 0)
+		// Minimum execution time: 2_446_000 picoseconds.
+		Weight::from_parts(2_613_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_079_000 picoseconds.
-		Weight::from_parts(1_141_000, 0)
+		// Minimum execution time: 960_000 picoseconds.
+		Weight::from_parts(1_045_000, 0)
 	}
 	pub fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 776_000 picoseconds.
-		Weight::from_parts(829_000, 0)
+		// Minimum execution time: 703_000 picoseconds.
+		Weight::from_parts(739_000, 0)
 	}
 	pub fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 696_000 picoseconds.
-		Weight::from_parts(740_000, 0)
+		// Minimum execution time: 616_000 picoseconds.
+		Weight::from_parts(651_000, 0)
 	}
 	pub fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 655_000 picoseconds.
-		Weight::from_parts(684_000, 0)
+		// Minimum execution time: 621_000 picoseconds.
+		Weight::from_parts(660_000, 0)
 	}
 	pub fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 825_000 picoseconds.
-		Weight::from_parts(853_000, 0)
+		// Minimum execution time: 794_000 picoseconds.
+		Weight::from_parts(831_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -256,8 +263,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 30_222_000 picoseconds.
-		Weight::from_parts(31_110_000, 3535)
+		// Minimum execution time: 29_527_000 picoseconds.
+		Weight::from_parts(30_614_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -265,8 +272,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_108_000 picoseconds.
-		Weight::from_parts(3_325_000, 0)
+		// Minimum execution time: 3_189_000 picoseconds.
+		Weight::from_parts(3_296_000, 0)
 	}
 	// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
 	// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
@@ -284,8 +291,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `70`
 		//  Estimated: `3535`
-		// Minimum execution time: 26_548_000 picoseconds.
-		Weight::from_parts(26_911_000, 3535)
+		// Minimum execution time: 25_965_000 picoseconds.
+		Weight::from_parts(26_468_000, 3535)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -293,35 +300,42 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 684_000 picoseconds.
-		Weight::from_parts(726_000, 0)
+		// Minimum execution time: 618_000 picoseconds.
+		Weight::from_parts(659_000, 0)
 	}
 	pub fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 649_000 picoseconds.
-		Weight::from_parts(700_000, 0)
+		// Minimum execution time: 593_000 picoseconds.
+		Weight::from_parts(618_000, 0)
 	}
 	pub fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 650_000 picoseconds.
-		Weight::from_parts(686_000, 0)
+		// Minimum execution time: 603_000 picoseconds.
+		Weight::from_parts(634_000, 0)
 	}
 	pub fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 652_000 picoseconds.
-		Weight::from_parts(703_000, 0)
+		// Minimum execution time: 568_000 picoseconds.
+		Weight::from_parts(629_000, 0)
 	}
 	pub fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 673_000 picoseconds.
-		Weight::from_parts(742_000, 0)
+		// Minimum execution time: 598_000 picoseconds.
+		Weight::from_parts(655_000, 0)
+	}
+	pub fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs
index bec5b923d8a..25256495ef9 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs
@@ -34,7 +34,7 @@ use parachains_common::{
 };
 use polkadot_parachain_primitives::primitives::Sibling;
 use sp_runtime::traits::AccountIdConversion;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
 	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
@@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor;
 parameter_types! {
 	pub const RootLocation: Location = Location::here();
 	pub const RelayLocation: Location = Location::parent();
-	pub const RelayNetwork: Option<NetworkId> = Some(NetworkId::Westend);
+	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();
diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs
index 36cf2bf4f83..05ecf6ca8e8 100644
--- a/cumulus/parachains/runtimes/test-utils/src/lib.rs
+++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs
@@ -441,15 +441,11 @@ impl<
 		AllPalletsWithoutSystem,
 	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
 {
-	pub fn execute_as_governance(call: Vec<u8>, require_weight_at_most: Weight) -> Outcome {
+	pub fn execute_as_governance(call: Vec<u8>) -> Outcome {
 		// prepare xcm as governance will do
 		let xcm = Xcm(vec![
 			UnpaidExecution { weight_limit: Unlimited, check_origin: None },
-			Transact {
-				origin_kind: OriginKind::Superuser,
-				require_weight_at_most,
-				call: call.into(),
-			},
+			Transact { origin_kind: OriginKind::Superuser, call: call.into() },
 			ExpectTransactStatus(MaybeErrorCode::Success),
 		]);
 
@@ -473,11 +469,7 @@ impl<
 		let xcm = Xcm(vec![
 			WithdrawAsset(buy_execution_fee.clone().into()),
 			BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
-			Transact {
-				origin_kind: OriginKind::Xcm,
-				require_weight_at_most: call.get_dispatch_info().call_weight,
-				call: call.encode().into(),
-			},
+			Transact { origin_kind: OriginKind::Xcm, call: call.encode().into() },
 			ExpectTransactStatus(MaybeErrorCode::Success),
 		]);
 
diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
index 1c58df189b6..a66163154cf 100644
--- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
@@ -72,17 +72,9 @@ pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, Sto
 					)],
 				});
 
-			// estimate - storing just 1 value
-			use frame_system::WeightInfo;
-			let require_weight_at_most =
-				<Runtime as frame_system::Config>::SystemWeightInfo::set_storage(1);
-
 			// execute XCM with Transact to `set_storage` as governance does
-			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
-				set_storage_call,
-				require_weight_at_most
-			)
-			.ensure_complete());
+			assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(set_storage_call,)
+				.ensure_complete());
 
 			// check delivery reward constant after (stored)
 			assert_eq!(StorageConstant::get(), new_storage_constant_value);
@@ -127,19 +119,10 @@ pub fn set_storage_keys_by_governance_works<Runtime>(
 			items: storage_items.clone(),
 		});
 
-		// estimate - storing just 1 value
-		use frame_system::WeightInfo;
-		let require_weight_at_most =
-			<Runtime as frame_system::Config>::SystemWeightInfo::set_storage(
-				storage_items.len().try_into().unwrap(),
-			);
-
 		// execute XCM with Transact to `set_storage` as governance does
-		assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
-			kill_storage_call,
-			require_weight_at_most
-		)
-		.ensure_complete());
+		assert_ok!(
+			RuntimeHelper::<Runtime>::execute_as_governance(kill_storage_call,).ensure_complete()
+		);
 	});
 	runtime.execute_with(|| {
 		assert_storage();
diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml
index 14c4fe52038..3a6b9d42f21 100644
--- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml
+++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml
@@ -79,6 +79,7 @@ pallet-collator-selection = { workspace = true }
 parachain-info = { workspace = true }
 parachains-common = { workspace = true }
 assets-common = { workspace = true }
+snowbridge-router-primitives = { workspace = true }
 
 primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] }
 
@@ -123,6 +124,7 @@ std = [
 	"polkadot-runtime-common/std",
 	"primitive-types/std",
 	"scale-info/std",
+	"snowbridge-router-primitives/std",
 	"sp-api/std",
 	"sp-block-builder/std",
 	"sp-consensus-aura/std",
@@ -168,6 +170,7 @@ runtime-benchmarks = [
 	"polkadot-parachain-primitives/runtime-benchmarks",
 	"polkadot-primitives/runtime-benchmarks",
 	"polkadot-runtime-common/runtime-benchmarks",
+	"snowbridge-router-primitives/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 	"xcm-builder/runtime-benchmarks",
 	"xcm-executor/runtime-benchmarks",
diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
index 6c9e3f7f23a..b51670c792d 100644
--- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs
@@ -36,6 +36,7 @@ extern crate alloc;
 
 use alloc::{vec, vec::Vec};
 use assets_common::{
+	foreign_creators::ForeignCreators,
 	local_and_foreign_assets::{LocalFromLeft, TargetFromLeft},
 	AssetIdForTrustBackedAssetsConvert,
 };
@@ -82,7 +83,7 @@ pub use sp_runtime::{traits::ConvertInto, MultiAddress, Perbill, Permill};
 #[cfg(feature = "std")]
 use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-use xcm_config::{ForeignAssetsAssetId, XcmOriginToTransactDispatchOrigin};
+use xcm_config::{ForeignAssetsAssetId, LocationToAccountId, XcmOriginToTransactDispatchOrigin};
 
 #[cfg(any(feature = "std", test))]
 pub use sp_runtime::BuildStorage;
@@ -494,7 +495,10 @@ impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
 	type AssetId = ForeignAssetsAssetId;
 	type AssetIdParameter = ForeignAssetsAssetId;
 	type Currency = Balances;
-	type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
+	// This is to allow any other remote location to create foreign assets. Used in tests, not
+	// recommended on real chains.
+	type CreateOrigin =
+		ForeignCreators<Everything, LocationToAccountId, AccountId, xcm::latest::Location>;
 	type ForceOrigin = EnsureRoot<AccountId>;
 	type AssetDeposit = ForeignAssetsAssetDeposit;
 	type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs
index b72d6d232a1..375c3d509f4 100644
--- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs
+++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs
@@ -44,13 +44,15 @@ use pallet_xcm::XcmPassthrough;
 use parachains_common::{xcm_config::AssetFeeAsExistentialDepositMultiplier, TREASURY_PALLET_ID};
 use polkadot_parachain_primitives::primitives::Sibling;
 use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice};
+use snowbridge_router_primitives::inbound::EthereumLocationsConverterFor;
 use sp_runtime::traits::{AccountIdConversion, ConvertInto, Identity, TryConvertInto};
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
-	AccountId32Aliases, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses,
-	AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
-	ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FixedWeightBounds,
-	FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete,
+	AccountId32Aliases, AliasOriginRootUsingFilter, AllowHrmpNotificationsFromRelayChain,
+	AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
+	AsPrefixedGeneralIndex, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily,
+	EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter,
+	FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete,
 	LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
 	SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia,
 	SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter,
@@ -65,8 +67,8 @@ parameter_types! {
 	pub const PenpalNativeCurrency: Location = Location::here();
 	// The Penpal runtime is utilized for testing with various environment setups.
 	// This storage item allows us to customize the `NetworkId` where Penpal is deployed.
-	// By default, it is set to `NetworkId::Rococo` and can be changed using `System::set_storage`.
-	pub storage RelayNetworkId: NetworkId = NetworkId::Westend;
+	// By default, it is set to `Westend Network` and can be changed using `System::set_storage`.
+	pub storage RelayNetworkId: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
 	pub RelayNetwork: Option<NetworkId> = Some(RelayNetworkId::get());
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation = [
@@ -92,6 +94,12 @@ pub type LocationToAccountId = (
 	AccountId32Aliases<RelayNetwork, AccountId>,
 	// Foreign locations alias into accounts according to a hash of their standard description.
 	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
+	// Different global consensus parachain sovereign account.
+	// (Used for over-bridge transfers and reserve processing)
+	GlobalConsensusParachainConvertsFor<UniversalLocation, AccountId>,
+	// Ethereum contract sovereign account.
+	// (Used to get convert ethereum contract locations to sovereign account)
+	EthereumLocationsConverterFor<AccountId>,
 );
 
 /// Means for transacting assets on this chain.
@@ -398,7 +406,8 @@ impl xcm_executor::Config for XcmConfig {
 	type UniversalAliases = Nothing;
 	type CallDispatcher = RuntimeCall;
 	type SafeCallFilter = Everything;
-	type Aliasers = Nothing;
+	// We allow trusted Asset Hub root to alias other locations.
+	type Aliasers = AliasOriginRootUsingFilter<SystemAssetHubLocation, Everything>;
 	type TransactionalProcessor = FrameTransactionalProcessor;
 	type HrmpNewChannelOpenRequestHandler = ();
 	type HrmpChannelAcceptedHandler = ();
diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
index 095f571974f..42556e0b493 100644
--- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
+++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs
@@ -85,7 +85,7 @@ use xcm_executor::traits::JustTry;
 // XCM imports
 use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough};
 use polkadot_parachain_primitives::primitives::Sibling;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom,
 	EnsureXcmOrigin, FixedWeightBounds, FungibleAdapter, IsConcrete, NativeAsset,
@@ -332,7 +332,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {}
 
 parameter_types! {
 	pub const RocLocation: Location = Location::parent();
-	pub const RococoNetwork: NetworkId = NetworkId::Rococo;
+	pub const RococoNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
 	pub UniversalLocation: InteriorLocation = [GlobalConsensus(RococoNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
 	pub CheckingAccount: AccountId = PolkadotXcm::check_account();
diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs
index b91246a7bda..ff14b747973 100644
--- a/cumulus/xcm/xcm-emulator/src/lib.rs
+++ b/cumulus/xcm/xcm-emulator/src/lib.rs
@@ -36,7 +36,10 @@ pub use core::{cell::RefCell, fmt::Debug};
 pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessageOrigin;
 pub use frame_support::{
 	assert_ok,
-	sp_runtime::{traits::Header as HeaderT, DispatchResult},
+	sp_runtime::{
+		traits::{Dispatchable, Header as HeaderT},
+		DispatchResult,
+	},
 	traits::{
 		EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnInitialize, OriginTrait,
 		ProcessMessage, ProcessMessageError, ServiceQueues,
@@ -221,7 +224,7 @@ pub trait Network {
 pub trait Chain: TestExt {
 	type Network: Network;
 	type Runtime: SystemConfig;
-	type RuntimeCall;
+	type RuntimeCall: Clone + Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>;
 	type RuntimeOrigin;
 	type RuntimeEvent;
 	type System;
@@ -1221,7 +1224,7 @@ macro_rules! __impl_check_assertion {
 			Args: Clone,
 		{
 			fn check_assertion(test: $crate::Test<Origin, Destination, Hops, Args>) {
-				use $crate::TestExt;
+				use $crate::{Dispatchable, TestExt};
 
 				let chain_name = std::any::type_name::<$chain<$network>>();
 
@@ -1229,6 +1232,15 @@ macro_rules! __impl_check_assertion {
 					if let Some(dispatchable) = test.hops_dispatchable.get(chain_name) {
 						$crate::assert_ok!(dispatchable(test.clone()));
 					}
+					if let Some(call) = test.hops_calls.get(chain_name) {
+						$crate::assert_ok!(
+							match call.clone().dispatch(test.signed_origin.clone()) {
+								// We get rid of `post_info`.
+								Ok(_) => Ok(()),
+								Err(error_with_post_info) => Err(error_with_post_info.error),
+							}
+						);
+					}
 					if let Some(assertion) = test.hops_assertion.get(chain_name) {
 						assertion(test);
 					}
@@ -1530,11 +1542,12 @@ where
 	pub root_origin: Origin::RuntimeOrigin,
 	pub hops_assertion: HashMap<String, fn(Self)>,
 	pub hops_dispatchable: HashMap<String, fn(Self) -> DispatchResult>,
+	pub hops_calls: HashMap<String, Origin::RuntimeCall>,
 	pub args: Args,
 	_marker: PhantomData<(Destination, Hops)>,
 }
 
-/// `Test` implementation
+/// `Test` implementation.
 impl<Origin, Destination, Hops, Args> Test<Origin, Destination, Hops, Args>
 where
 	Args: Clone,
@@ -1544,7 +1557,7 @@ where
 	Destination::RuntimeOrigin: OriginTrait<AccountId = AccountIdOf<Destination::Runtime>> + Clone,
 	Hops: Clone + CheckAssertion<Origin, Destination, Hops, Args>,
 {
-	/// Creates a new `Test` instance
+	/// Creates a new `Test` instance.
 	pub fn new(test_args: TestContext<Args, Origin, Destination>) -> Self {
 		Test {
 			sender: TestAccount {
@@ -1559,6 +1572,7 @@ where
 			root_origin: <Origin as Chain>::RuntimeOrigin::root(),
 			hops_assertion: Default::default(),
 			hops_dispatchable: Default::default(),
+			hops_calls: Default::default(),
 			args: test_args.args,
 			_marker: Default::default(),
 		}
@@ -1573,6 +1587,11 @@ where
 		let chain_name = std::any::type_name::<Hop>();
 		self.hops_dispatchable.insert(chain_name.to_string(), dispatchable);
 	}
+	/// Stores a call in a particular Chain, this will later be dispatched.
+	pub fn set_call(&mut self, call: Origin::RuntimeCall) {
+		let chain_name = std::any::type_name::<Origin>();
+		self.hops_calls.insert(chain_name.to_string(), call);
+	}
 	/// Executes all dispatchables and assertions in order from `Origin` to `Destination`
 	pub fn assert(&mut self) {
 		Origin::check_assertion(self.clone());
diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs
index 2f79d223d3c..9a290f08609 100644
--- a/polkadot/runtime/common/src/impls.rs
+++ b/polkadot/runtime/common/src/impls.rs
@@ -138,6 +138,15 @@ pub enum VersionedLocatableAsset {
 	V3 { location: xcm::v3::Location, asset_id: xcm::v3::AssetId },
 	#[codec(index = 4)]
 	V4 { location: xcm::v4::Location, asset_id: xcm::v4::AssetId },
+	#[codec(index = 5)]
+	V5 { location: xcm::v5::Location, asset_id: xcm::v5::AssetId },
+}
+
+/// A conversion from latest xcm to `VersionedLocatableAsset`.
+impl From<(xcm::latest::Location, xcm::latest::AssetId)> for VersionedLocatableAsset {
+	fn from(value: (xcm::latest::Location, xcm::latest::AssetId)) -> Self {
+		VersionedLocatableAsset::V5 { location: value.0, asset_id: value.1 }
+	}
 }
 
 /// Converts the [`VersionedLocatableAsset`] to the [`xcm_builder::LocatableAssetId`].
@@ -149,12 +158,22 @@ impl TryConvert<VersionedLocatableAsset, xcm_builder::LocatableAssetId>
 		asset: VersionedLocatableAsset,
 	) -> Result<xcm_builder::LocatableAssetId, VersionedLocatableAsset> {
 		match asset {
-			VersionedLocatableAsset::V3 { location, asset_id } =>
+			VersionedLocatableAsset::V3 { location, asset_id } => {
+				let v4_location: xcm::v4::Location =
+					location.try_into().map_err(|_| asset.clone())?;
+				let v4_asset_id: xcm::v4::AssetId =
+					asset_id.try_into().map_err(|_| asset.clone())?;
+				Ok(xcm_builder::LocatableAssetId {
+					location: v4_location.try_into().map_err(|_| asset.clone())?,
+					asset_id: v4_asset_id.try_into().map_err(|_| asset.clone())?,
+				})
+			},
+			VersionedLocatableAsset::V4 { ref location, ref asset_id } =>
 				Ok(xcm_builder::LocatableAssetId {
-					location: location.try_into().map_err(|_| asset.clone())?,
-					asset_id: asset_id.try_into().map_err(|_| asset.clone())?,
+					location: location.clone().try_into().map_err(|_| asset.clone())?,
+					asset_id: asset_id.clone().try_into().map_err(|_| asset.clone())?,
 				}),
-			VersionedLocatableAsset::V4 { location, asset_id } =>
+			VersionedLocatableAsset::V5 { location, asset_id } =>
 				Ok(xcm_builder::LocatableAssetId { location, asset_id }),
 		}
 	}
@@ -167,12 +186,12 @@ impl TryConvert<&VersionedLocation, xcm::latest::Location> for VersionedLocation
 		location: &VersionedLocation,
 	) -> Result<xcm::latest::Location, &VersionedLocation> {
 		let latest = match location.clone() {
-			VersionedLocation::V2(l) => {
-				let v3: xcm::v3::Location = l.try_into().map_err(|_| location)?;
-				v3.try_into().map_err(|_| location)?
+			VersionedLocation::V3(l) => {
+				let v4_location: xcm::v4::Location = l.try_into().map_err(|_| location)?;
+				v4_location.try_into().map_err(|_| location)?
 			},
-			VersionedLocation::V3(l) => l.try_into().map_err(|_| location)?,
-			VersionedLocation::V4(l) => l,
+			VersionedLocation::V4(l) => l.try_into().map_err(|_| location)?,
+			VersionedLocation::V5(l) => l,
 		};
 		Ok(latest)
 	}
@@ -188,11 +207,25 @@ where
 	fn contains(asset: &VersionedLocatableAsset) -> bool {
 		use VersionedLocatableAsset::*;
 		let (location, asset_id) = match asset.clone() {
-			V3 { location, asset_id } => match (location.try_into(), asset_id.try_into()) {
+			V3 { location, asset_id } => {
+				let v4_location: xcm::v4::Location = match location.try_into() {
+					Ok(l) => l,
+					Err(_) => return false,
+				};
+				let v4_asset_id: xcm::v4::AssetId = match asset_id.try_into() {
+					Ok(a) => a,
+					Err(_) => return false,
+				};
+				match (v4_location.try_into(), v4_asset_id.try_into()) {
+					(Ok(l), Ok(a)) => (l, a),
+					_ => return false,
+				}
+			},
+			V4 { location, asset_id } => match (location.try_into(), asset_id.try_into()) {
 				(Ok(l), Ok(a)) => (l, a),
 				_ => return false,
 			},
-			V4 { location, asset_id } => (location, asset_id),
+			V5 { location, asset_id } => (location, asset_id),
 		};
 		C::contains(&location, &asset_id.0)
 	}
@@ -213,17 +246,14 @@ pub mod benchmarks {
 	pub struct AssetRateArguments;
 	impl AssetKindFactory<VersionedLocatableAsset> for AssetRateArguments {
 		fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
-			VersionedLocatableAsset::V4 {
-				location: xcm::v4::Location::new(0, [xcm::v4::Junction::Parachain(seed)]),
-				asset_id: xcm::v4::Location::new(
+			(
+				Location::new(0, [Parachain(seed)]),
+				AssetId(Location::new(
 					0,
-					[
-						xcm::v4::Junction::PalletInstance(seed.try_into().unwrap()),
-						xcm::v4::Junction::GeneralIndex(seed.into()),
-					],
-				)
-				.into(),
-			}
+					[PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())],
+				)),
+			)
+				.into()
 		}
 	}
 
@@ -238,26 +268,17 @@ pub mod benchmarks {
 		for TreasuryArguments<Parents, ParaId>
 	{
 		fn create_asset_kind(seed: u32) -> VersionedLocatableAsset {
-			VersionedLocatableAsset::V3 {
-				location: xcm::v3::Location::new(
-					Parents::get(),
-					[xcm::v3::Junction::Parachain(ParaId::get())],
-				),
-				asset_id: xcm::v3::Location::new(
+			(
+				Location::new(Parents::get(), [Junction::Parachain(ParaId::get())]),
+				AssetId(Location::new(
 					0,
-					[
-						xcm::v3::Junction::PalletInstance(seed.try_into().unwrap()),
-						xcm::v3::Junction::GeneralIndex(seed.into()),
-					],
-				)
-				.into(),
-			}
+					[PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())],
+				)),
+			)
+				.into()
 		}
 		fn create_beneficiary(seed: [u8; 32]) -> VersionedLocation {
-			VersionedLocation::V4(xcm::v4::Location::new(
-				0,
-				[xcm::v4::Junction::AccountId32 { network: None, id: seed }],
-			))
+			VersionedLocation::from(Location::new(0, [AccountId32 { network: None, id: seed }]))
 		}
 	}
 }
diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs
index 37fe7f0b59e..7ff7f69faf1 100644
--- a/polkadot/runtime/common/src/xcm_sender.rs
+++ b/polkadot/runtime/common/src/xcm_sender.rs
@@ -157,7 +157,7 @@ impl<T: dmp::Config, W, P> InspectMessageQueues for ChildParachainRouter<T, W, P
 						message
 					})
 					.collect();
-				(VersionedLocation::V4(Parachain(para_id.into()).into()), decoded_messages)
+				(VersionedLocation::from(Location::from(Parachain(para_id.into()))), decoded_messages)
 			})
 			.collect()
 	}
diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs
index 52189be3d24..c3a1ebe8243 100644
--- a/polkadot/runtime/parachains/src/coretime/migration.rs
+++ b/polkadot/runtime/parachains/src/coretime/migration.rs
@@ -42,7 +42,9 @@ mod v_coretime {
 	use sp_arithmetic::traits::SaturatedConversion;
 	use sp_core::Get;
 	use sp_runtime::BoundedVec;
-	use xcm::prelude::{send_xcm, Instruction, Junction, Location, SendError, WeightLimit, Xcm};
+	use xcm::prelude::{
+		send_xcm, Instruction, Junction, Location, SendError, SendXcm, WeightLimit, Xcm,
+	};
 
 	/// Return information about a legacy lease of a parachain.
 	pub trait GetLegacyLease<N> {
@@ -62,10 +64,10 @@ mod v_coretime {
 
 	impl<
 			T: Config,
-			SendXcm: xcm::v4::SendXcm,
+			XcmSender: SendXcm,
 			LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
 			const TIMESLICE_PERIOD: u32,
-		> MigrateToCoretime<T, SendXcm, LegacyLease, TIMESLICE_PERIOD>
+		> MigrateToCoretime<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>
 	{
 		fn already_migrated() -> bool {
 			// We are using the assigner coretime because the coretime pallet doesn't has any
@@ -95,10 +97,10 @@ mod v_coretime {
 
 	impl<
 			T: Config + crate::dmp::Config,
-			SendXcm: xcm::v4::SendXcm,
+			XcmSender: SendXcm,
 			LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
 			const TIMESLICE_PERIOD: u32,
-		> OnRuntimeUpgrade for MigrateToCoretime<T, SendXcm, LegacyLease, TIMESLICE_PERIOD>
+		> OnRuntimeUpgrade for MigrateToCoretime<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>
 	{
 		fn on_runtime_upgrade() -> Weight {
 			if Self::already_migrated() {
@@ -106,7 +108,7 @@ mod v_coretime {
 			}
 
 			log::info!("Migrating existing parachains to coretime.");
-			migrate_to_coretime::<T, SendXcm, LegacyLease, TIMESLICE_PERIOD>()
+			migrate_to_coretime::<T, XcmSender, LegacyLease, TIMESLICE_PERIOD>()
 		}
 
 		#[cfg(feature = "try-runtime")]
@@ -157,7 +159,7 @@ mod v_coretime {
 	// NOTE: Also migrates `num_cores` config value in configuration::ActiveConfig.
 	fn migrate_to_coretime<
 		T: Config,
-		SendXcm: xcm::v4::SendXcm,
+		XcmSender: SendXcm,
 		LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
 		const TIMESLICE_PERIOD: u32,
 	>() -> Weight {
@@ -198,9 +200,12 @@ mod v_coretime {
 			c.scheduler_params.num_cores = total_cores;
 		});
 
-		if let Err(err) =
-			migrate_send_assignments_to_coretime_chain::<T, SendXcm, LegacyLease, TIMESLICE_PERIOD>(
-			) {
+		if let Err(err) = migrate_send_assignments_to_coretime_chain::<
+			T,
+			XcmSender,
+			LegacyLease,
+			TIMESLICE_PERIOD,
+		>() {
 			log::error!("Sending legacy chain data to coretime chain failed: {:?}", err);
 		}
 
@@ -215,7 +220,7 @@ mod v_coretime {
 
 	fn migrate_send_assignments_to_coretime_chain<
 		T: Config,
-		SendXcm: xcm::v4::SendXcm,
+		XcmSender: SendXcm,
 		LegacyLease: GetLegacyLease<BlockNumberFor<T>>,
 		const TIMESLICE_PERIOD: u32,
 	>() -> result::Result<(), SendError> {
@@ -300,7 +305,7 @@ mod v_coretime {
 		};
 
 		for message in messages {
-			send_xcm::<SendXcm>(
+			send_xcm::<XcmSender>(
 				Location::new(0, Junction::Parachain(T::BrokerId::get())),
 				message,
 			)?;
diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs
index 9b9bdb86878..966b7997a27 100644
--- a/polkadot/runtime/parachains/src/coretime/mod.rs
+++ b/polkadot/runtime/parachains/src/coretime/mod.rs
@@ -30,20 +30,7 @@ use pallet_broker::{CoreAssignment, CoreIndex as BrokerCoreIndex};
 use polkadot_primitives::{Balance, BlockNumber, CoreIndex, Id as ParaId};
 use sp_arithmetic::traits::SaturatedConversion;
 use sp_runtime::traits::TryConvert;
-use xcm::{
-	prelude::{send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm},
-	v4::{
-		Asset,
-		AssetFilter::Wild,
-		AssetId, Assets, Error as XcmError,
-		Fungibility::Fungible,
-		Instruction::{DepositAsset, ReceiveTeleportedAsset},
-		Junctions::Here,
-		Reanchorable,
-		WildAsset::AllCounted,
-		XcmContext,
-	},
-};
+use xcm::prelude::*;
 use xcm_executor::traits::TransactAsset;
 
 use crate::{
@@ -119,7 +106,7 @@ pub mod pallet {
 
 	use crate::configuration;
 	use sp_runtime::traits::TryConvert;
-	use xcm::v4::InteriorLocation;
+	use xcm::latest::InteriorLocation;
 	use xcm_executor::traits::TransactAsset;
 
 	use super::*;
@@ -149,11 +136,6 @@ pub mod pallet {
 		type AssetTransactor: TransactAsset;
 		/// AccountId to Location converter
 		type AccountToLocation: for<'a> TryConvert<&'a Self::AccountId, Location>;
-
-		/// Maximum weight for any XCM transact call that should be executed on the coretime chain.
-		///
-		/// Basically should be `max_weight(set_leases, reserve, notify_core_count)`.
-		type MaxXcmTransactWeight: Get<Weight>;
 	}
 
 	#[pallet::event]
@@ -351,7 +333,6 @@ impl<T: Config> OnNewSession<BlockNumberFor<T>> for Pallet<T> {
 fn mk_coretime_call<T: Config>(call: crate::coretime::CoretimeCalls) -> Instruction<()> {
 	Instruction::Transact {
 		origin_kind: OriginKind::Superuser,
-		require_weight_at_most: T::MaxXcmTransactWeight::get(),
 		call: BrokerRuntimePallets::Broker(call).encode().into(),
 	}
 }
@@ -362,7 +343,7 @@ fn do_notify_revenue<T: Config>(when: BlockNumber, raw_revenue: Balance) -> Resu
 		weight_limit: WeightLimit::Unlimited,
 		check_origin: None,
 	}];
-	let asset = Asset { id: AssetId(Location::here()), fun: Fungible(raw_revenue) };
+	let asset = Asset { id: Location::here().into(), fun: Fungible(raw_revenue) };
 	let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None };
 
 	if raw_revenue > 0 {
diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs
index 9ef3922f0f8..d701e1f9bd8 100644
--- a/polkadot/runtime/parachains/src/mock.rs
+++ b/polkadot/runtime/parachains/src/mock.rs
@@ -30,7 +30,9 @@ use polkadot_primitives::CoreIndex;
 
 use codec::Decode;
 use frame_support::{
-	assert_ok, derive_impl, parameter_types,
+	assert_ok, derive_impl,
+	dispatch::GetDispatchInfo,
+	parameter_types,
 	traits::{
 		Currency, ProcessMessage, ProcessMessageError, ValidatorSet, ValidatorSetWithIdentification,
 	},
@@ -56,7 +58,7 @@ use std::{
 };
 use xcm::{
 	prelude::XcmVersion,
-	v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash},
+	v5::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash},
 	IntoVersion, VersionedXcm, WrapVersion,
 };
 
@@ -260,7 +262,7 @@ thread_local! {
 /// versions in the `VERSION_WRAPPER`.
 pub struct TestUsesOnlyStoredVersionWrapper;
 impl WrapVersion for TestUsesOnlyStoredVersionWrapper {
-	fn wrap_version<RuntimeCall>(
+	fn wrap_version<RuntimeCall: Decode + GetDispatchInfo>(
 		dest: &Location,
 		xcm: impl Into<VersionedXcm<RuntimeCall>>,
 	) -> Result<VersionedXcm<RuntimeCall>, ()> {
@@ -419,7 +421,6 @@ impl assigner_coretime::Config for Test {}
 
 parameter_types! {
 	pub const BrokerId: u32 = 10u32;
-	pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000);
 }
 
 pub struct BrokerPot;
@@ -436,7 +437,6 @@ impl coretime::Config for Test {
 	type BrokerId = BrokerId;
 	type WeightInfo = crate::coretime::TestWeightInfo;
 	type SendXcm = DummyXcmSender;
-	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 	type BrokerPotLocation = BrokerPot;
 	type AssetTransactor = ();
 	type AccountToLocation = ();
diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs
index f01440ea02b..ab796edc54b 100644
--- a/polkadot/runtime/rococo/src/impls.rs
+++ b/polkadot/runtime/rococo/src/impls.rs
@@ -21,7 +21,7 @@ use core::marker::PhantomData;
 use frame_support::pallet_prelude::DispatchResult;
 use frame_system::RawOrigin;
 use polkadot_primitives::Balance;
-use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
+use polkadot_runtime_common::identity_migrator::OnReapIdentity;
 use rococo_runtime_constants::currency::*;
 use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
 use xcm_executor::traits::TransactAsset;
@@ -88,10 +88,7 @@ where
 	AccountId: Into<[u8; 32]> + Clone + Encode,
 {
 	fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult {
-		use crate::{
-			impls::IdentityMigratorCalls::PokeDeposit,
-			weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights,
-		};
+		use crate::impls::IdentityMigratorCalls::PokeDeposit;
 
 		let total_to_send = Self::calculate_remote_deposit(fields, subs);
 
@@ -144,7 +141,6 @@ where
 				.into();
 
 		let poke = PeopleRuntimePallets::<AccountId>::IdentityMigrator(PokeDeposit(who.clone()));
-		let remote_weight_limit = MigratorWeights::<Runtime>::poke_deposit().saturating_mul(2);
 
 		// Actual program to execute on People Chain.
 		let program: Xcm<()> = Xcm(vec![
@@ -161,18 +157,14 @@ where
 					.into(),
 			},
 			// Poke the deposit to reserve the appropriate amount on the parachain.
-			Transact {
-				origin_kind: OriginKind::Superuser,
-				require_weight_at_most: remote_weight_limit,
-				call: poke.encode().into(),
-			},
+			Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() },
 		]);
 
 		// send
 		let _ = <pallet_xcm::Pallet<Runtime>>::send(
 			RawOrigin::Root.into(),
-			Box::new(VersionedLocation::V4(destination)),
-			Box::new(VersionedXcm::V4(program)),
+			Box::new(VersionedLocation::from(destination)),
+			Box::new(VersionedXcm::from(program)),
 		)?;
 		Ok(())
 	}
diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs
index f8f8573bc90..96a97faa475 100644
--- a/polkadot/runtime/rococo/src/lib.rs
+++ b/polkadot/runtime/rococo/src/lib.rs
@@ -1098,7 +1098,6 @@ impl parachains_scheduler::Config for Runtime {
 parameter_types! {
 	pub const BrokerId: u32 = BROKER_ID;
 	pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
-	pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000);
 }
 
 pub struct BrokerPot;
@@ -1122,7 +1121,6 @@ impl coretime::Config for Runtime {
 		xcm_config::ThisNetwork,
 		<Runtime as frame_system::Config>::AccountId,
 	>;
-	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
index bd2b0fbb8c0..007002bf27b 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
@@ -24,6 +24,7 @@ use xcm::{latest::prelude::*, DoubleEncoded};
 
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
+use xcm::latest::AssetTransferFilter;
 
 /// Types of asset supported by the Rococo runtime.
 pub enum AssetTypes {
@@ -110,11 +111,7 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_kind: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<RuntimeCall>,
-	) -> Weight {
+	fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded<RuntimeCall>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -163,12 +160,35 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -266,6 +286,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
 }
 
 #[test]
diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index 7d743b20912..c1d5c3fc89d 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -55,8 +55,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_672_000 picoseconds.
-		Weight::from_parts(31_677_000, 3593)
+		// Minimum execution time: 32_017_000 picoseconds.
+		Weight::from_parts(32_841_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -66,8 +66,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 41_132_000 picoseconds.
-		Weight::from_parts(41_654_000, 6196)
+		// Minimum execution time: 42_570_000 picoseconds.
+		Weight::from_parts(43_526_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -85,8 +85,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `6196`
-		// Minimum execution time: 97_174_000 picoseconds.
-		Weight::from_parts(99_537_000, 6196)
+		// Minimum execution time: 103_020_000 picoseconds.
+		Weight::from_parts(104_906_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -113,8 +113,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `3746`
-		// Minimum execution time: 67_105_000 picoseconds.
-		Weight::from_parts(68_659_000, 3746)
+		// Minimum execution time: 70_944_000 picoseconds.
+		Weight::from_parts(73_630_000, 3746)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -124,8 +124,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3593`
-		// Minimum execution time: 30_780_000 picoseconds.
-		Weight::from_parts(31_496_000, 3593)
+		// Minimum execution time: 31_979_000 picoseconds.
+		Weight::from_parts(32_649_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -135,8 +135,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 23_411_000 picoseconds.
-		Weight::from_parts(23_891_000, 3593)
+		// Minimum execution time: 24_462_000 picoseconds.
+		Weight::from_parts(25_052_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -154,8 +154,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 61_541_000 picoseconds.
-		Weight::from_parts(63_677_000, 3645)
+		// Minimum execution time: 65_047_000 picoseconds.
+		Weight::from_parts(67_225_000, 3645)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -173,8 +173,27 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 48_574_000 picoseconds.
-		Weight::from_parts(49_469_000, 3645)
+		// Minimum execution time: 53_401_000 picoseconds.
+		Weight::from_parts(55_155_000, 3645)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
+	}
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	pub(crate) fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `180`
+		//  Estimated: `3645`
+		// Minimum execution time: 82_584_000 picoseconds.
+		Weight::from_parts(84_614_000, 3645)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index df2f9b2d0e8..677640b4533 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -16,28 +16,27 @@
 
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/polkadot
+// target/production/polkadot
 // benchmark
 // pallet
 // --steps=50
 // --repeat=20
 // --extrinsic=*
-// --execution=wasm
 // --wasm-execution=compiled
 // --heap-pages=4096
-// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
 // --pallet=pallet_xcm_benchmarks::generic
 // --chain=rococo-dev
-// --header=./file_header.txt
-// --template=./xcm/pallet-xcm-benchmarks/template.hbs
-// --output=./runtime/rococo/src/weights/xcm/
+// --header=./polkadot/file_header.txt
+// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs
+// --output=./polkadot/runtime/rococo/src/weights/xcm/
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -50,130 +49,125 @@ use core::marker::PhantomData;
 /// Weight functions for `pallet_xcm_benchmarks::generic`.
 pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo<T> {
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Configuration ActiveConfig (r:1 w:0)
-	/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_holding() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `565`
-		//  Estimated: `4030`
-		// Minimum execution time: 36_305_000 picoseconds.
-		Weight::from_parts(37_096_000, 4030)
-			.saturating_add(T::DbWeight::get().reads(8))
-			.saturating_add(T::DbWeight::get().writes(4))
+		//  Measured:  `281`
+		//  Estimated: `3746`
+		// Minimum execution time: 64_284_000 picoseconds.
+		Weight::from_parts(65_590_000, 3746)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
 	pub(crate) fn buy_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_831_000 picoseconds.
-		Weight::from_parts(2_904_000, 0)
+		// Minimum execution time: 777_000 picoseconds.
+		Weight::from_parts(825_000, 0)
 	}
-	/// Storage: XcmPallet Queries (r:1 w:0)
-	/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
+	pub(crate) fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_543_000 picoseconds.
+		Weight::from_parts(1_627_000, 0)
+	}
+	/// Storage: `XcmPallet::Queries` (r:1 w:0)
+	/// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn query_response() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 11_769_000 picoseconds.
-		Weight::from_parts(12_122_000, 3634)
+		//  Measured:  `0`
+		//  Estimated: `3465`
+		// Minimum execution time: 5_995_000 picoseconds.
+		Weight::from_parts(6_151_000, 3465)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub(crate) fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 12_293_000 picoseconds.
-		Weight::from_parts(12_522_000, 0)
+		// Minimum execution time: 7_567_000 picoseconds.
+		Weight::from_parts(7_779_000, 0)
 	}
 	pub(crate) fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_858_000 picoseconds.
-		Weight::from_parts(2_965_000, 0)
+		// Minimum execution time: 1_226_000 picoseconds.
+		Weight::from_parts(1_322_000, 0)
 	}
 	pub(crate) fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_623_000 picoseconds.
-		Weight::from_parts(2_774_000, 0)
+		// Minimum execution time: 768_000 picoseconds.
+		Weight::from_parts(828_000, 0)
 	}
 	pub(crate) fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_664_000 picoseconds.
-		Weight::from_parts(2_752_000, 0)
+		// Minimum execution time: 765_000 picoseconds.
+		Weight::from_parts(814_000, 0)
 	}
 	pub(crate) fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_646_000 picoseconds.
-		Weight::from_parts(2_709_000, 0)
+		// Minimum execution time: 739_000 picoseconds.
+		Weight::from_parts(820_000, 0)
 	}
 	pub(crate) fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_602_000 picoseconds.
-		Weight::from_parts(3_669_000, 0)
+		// Minimum execution time: 806_000 picoseconds.
+		Weight::from_parts(849_000, 0)
 	}
 	pub(crate) fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_609_000 picoseconds.
-		Weight::from_parts(2_721_000, 0)
+		// Minimum execution time: 782_000 picoseconds.
+		Weight::from_parts(820_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Configuration ActiveConfig (r:1 w:0)
-	/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_error() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `565`
-		//  Estimated: `4030`
-		// Minimum execution time: 31_776_000 picoseconds.
-		Weight::from_parts(32_354_000, 4030)
-			.saturating_add(T::DbWeight::get().reads(8))
-			.saturating_add(T::DbWeight::get().writes(4))
+		//  Measured:  `281`
+		//  Estimated: `3746`
+		// Minimum execution time: 61_410_000 picoseconds.
+		Weight::from_parts(62_813_000, 3746)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
-	/// Storage: XcmPallet AssetTraps (r:1 w:1)
-	/// Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::AssetTraps` (r:1 w:1)
+	/// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn claim_asset() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `226`
-		//  Estimated: `3691`
-		// Minimum execution time: 15_912_000 picoseconds.
-		Weight::from_parts(16_219_000, 3691)
+		//  Measured:  `23`
+		//  Estimated: `3488`
+		// Minimum execution time: 9_315_000 picoseconds.
+		Weight::from_parts(9_575_000, 3488)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -181,171 +175,158 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_704_000 picoseconds.
-		Weight::from_parts(2_777_000, 0)
+		// Minimum execution time: 733_000 picoseconds.
+		Weight::from_parts(813_000, 0)
 	}
-	/// Storage: XcmPallet VersionNotifyTargets (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured)
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Configuration ActiveConfig (r:1 w:0)
-	/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1)
+	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn subscribe_version() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `565`
-		//  Estimated: `4030`
-		// Minimum execution time: 38_690_000 picoseconds.
-		Weight::from_parts(39_157_000, 4030)
-			.saturating_add(T::DbWeight::get().reads(9))
-			.saturating_add(T::DbWeight::get().writes(5))
+		//  Measured:  `180`
+		//  Estimated: `3645`
+		// Minimum execution time: 30_641_000 picoseconds.
+		Weight::from_parts(31_822_000, 3645)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
-	/// Storage: XcmPallet VersionNotifyTargets (r:0 w:1)
-	/// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1)
+	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn unsubscribe_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_943_000 picoseconds.
-		Weight::from_parts(5_128_000, 0)
+		// Minimum execution time: 2_978_000 picoseconds.
+		Weight::from_parts(3_260_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub(crate) fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 6_438_000 picoseconds.
-		Weight::from_parts(6_500_000, 0)
+		// Minimum execution time: 1_139_000 picoseconds.
+		Weight::from_parts(1_272_000, 0)
 	}
 	pub(crate) fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_773_000 picoseconds.
-		Weight::from_parts(4_840_000, 0)
+		// Minimum execution time: 850_000 picoseconds.
+		Weight::from_parts(879_000, 0)
 	}
 	pub(crate) fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_818_000 picoseconds.
-		Weight::from_parts(2_893_000, 0)
+		// Minimum execution time: 770_000 picoseconds.
+		Weight::from_parts(834_000, 0)
 	}
 	pub(crate) fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_611_000 picoseconds.
-		Weight::from_parts(2_708_000, 0)
+		// Minimum execution time: 756_000 picoseconds.
+		Weight::from_parts(797_000, 0)
 	}
 	pub(crate) fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_870_000 picoseconds.
-		Weight::from_parts(2_958_000, 0)
+		// Minimum execution time: 888_000 picoseconds.
+		Weight::from_parts(1_000_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Configuration ActiveConfig (r:1 w:0)
-	/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn query_pallet() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `565`
-		//  Estimated: `4030`
-		// Minimum execution time: 40_735_000 picoseconds.
-		Weight::from_parts(66_023_000, 4030)
-			.saturating_add(T::DbWeight::get().reads(8))
-			.saturating_add(T::DbWeight::get().writes(4))
+		//  Measured:  `281`
+		//  Estimated: `3746`
+		// Minimum execution time: 72_138_000 picoseconds.
+		Weight::from_parts(73_728_000, 3746)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
 	pub(crate) fn expect_pallet() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_293_000 picoseconds.
-		Weight::from_parts(18_088_000, 0)
+		// Minimum execution time: 8_482_000 picoseconds.
+		Weight::from_parts(8_667_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Configuration ActiveConfig (r:1 w:0)
-	/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_transact_status() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `565`
-		//  Estimated: `4030`
-		// Minimum execution time: 31_438_000 picoseconds.
-		Weight::from_parts(32_086_000, 4030)
-			.saturating_add(T::DbWeight::get().reads(8))
-			.saturating_add(T::DbWeight::get().writes(4))
+		//  Measured:  `281`
+		//  Estimated: `3746`
+		// Minimum execution time: 61_580_000 picoseconds.
+		Weight::from_parts(62_928_000, 3746)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
 	pub(crate) fn clear_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_676_000 picoseconds.
-		Weight::from_parts(2_746_000, 0)
+		// Minimum execution time: 807_000 picoseconds.
+		Weight::from_parts(844_000, 0)
 	}
 	pub(crate) fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_629_000 picoseconds.
-		Weight::from_parts(2_724_000, 0)
+		// Minimum execution time: 757_000 picoseconds.
+		Weight::from_parts(808_000, 0)
 	}
 	pub(crate) fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_602_000 picoseconds.
-		Weight::from_parts(2_671_000, 0)
+		// Minimum execution time: 740_000 picoseconds.
+		Weight::from_parts(810_000, 0)
 	}
 	pub(crate) fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_681_000 picoseconds.
-		Weight::from_parts(2_768_000, 0)
+		// Minimum execution time: 752_000 picoseconds.
+		Weight::from_parts(786_000, 0)
 	}
 	pub(crate) fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_764_000 picoseconds.
-		Weight::from_parts(2_865_000, 0)
+		// Minimum execution time: 798_000 picoseconds.
+		Weight::from_parts(845_000, 0)
+	}
+	pub(crate) fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
 	}
 }
diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs
index 05e0ee64820..82a3136cc0d 100644
--- a/polkadot/runtime/rococo/src/xcm_config.rs
+++ b/polkadot/runtime/rococo/src/xcm_config.rs
@@ -35,7 +35,7 @@ use polkadot_runtime_common::{
 };
 use rococo_runtime_constants::{currency::CENTS, system_parachain::*};
 use sp_core::ConstU32;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
 	AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
@@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor;
 parameter_types! {
 	pub TokenLocation: Location = Here.into_location();
 	pub RootLocation: Location = Location::here();
-	pub const ThisNetwork: NetworkId = NetworkId::Rococo;
+	pub const ThisNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
 	pub UniversalLocation: InteriorLocation = ThisNetwork::get().into();
 	pub CheckAccount: AccountId = XcmPallet::check_account();
 	pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs
index bb46b19956e..d2ed5abb6ed 100644
--- a/polkadot/runtime/test-runtime/src/lib.rs
+++ b/polkadot/runtime/test-runtime/src/lib.rs
@@ -93,7 +93,7 @@ use sp_staking::SessionIndex;
 #[cfg(any(feature = "std", test))]
 use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-use xcm::v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash};
+use xcm::latest::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash};
 
 pub use pallet_balances::Call as BalancesCall;
 #[cfg(feature = "std")]
@@ -584,7 +584,6 @@ impl parachains_paras::Config for Runtime {
 
 parameter_types! {
 	pub const BrokerId: u32 = 10u32;
-	pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000);
 }
 
 pub struct BrokerPot;
@@ -640,7 +639,7 @@ impl SendXcm for DummyXcmSender {
 	type Ticket = ();
 	fn validate(
 		_: &mut Option<Location>,
-		_: &mut Option<xcm::v4::Xcm<()>>,
+		_: &mut Option<xcm::latest::Xcm<()>>,
 	) -> SendResult<Self::Ticket> {
 		Ok(((), Assets::new()))
 	}
@@ -658,7 +657,6 @@ impl coretime::Config for Runtime {
 	type BrokerId = BrokerId;
 	type WeightInfo = crate::coretime::TestWeightInfo;
 	type SendXcm = DummyXcmSender;
-	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 	type BrokerPotLocation = BrokerPot;
 	type AssetTransactor = ();
 	type AccountToLocation = ();
diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs
index ac3f9e679f8..d7281dad56d 100644
--- a/polkadot/runtime/westend/src/impls.rs
+++ b/polkadot/runtime/westend/src/impls.rs
@@ -21,7 +21,7 @@ use core::marker::PhantomData;
 use frame_support::pallet_prelude::DispatchResult;
 use frame_system::RawOrigin;
 use polkadot_primitives::Balance;
-use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo};
+use polkadot_runtime_common::identity_migrator::OnReapIdentity;
 use westend_runtime_constants::currency::*;
 use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm};
 use xcm_executor::traits::TransactAsset;
@@ -88,10 +88,7 @@ where
 	AccountId: Into<[u8; 32]> + Clone + Encode,
 {
 	fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult {
-		use crate::{
-			impls::IdentityMigratorCalls::PokeDeposit,
-			weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights,
-		};
+		use crate::impls::IdentityMigratorCalls::PokeDeposit;
 
 		let total_to_send = Self::calculate_remote_deposit(fields, subs);
 
@@ -144,7 +141,6 @@ where
 				.into();
 
 		let poke = PeopleRuntimePallets::<AccountId>::IdentityMigrator(PokeDeposit(who.clone()));
-		let remote_weight_limit = MigratorWeights::<Runtime>::poke_deposit().saturating_mul(2);
 
 		// Actual program to execute on People Chain.
 		let program: Xcm<()> = Xcm(vec![
@@ -161,18 +157,14 @@ where
 					.into(),
 			},
 			// Poke the deposit to reserve the appropriate amount on the parachain.
-			Transact {
-				origin_kind: OriginKind::Superuser,
-				require_weight_at_most: remote_weight_limit,
-				call: poke.encode().into(),
-			},
+			Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() },
 		]);
 
 		// send
 		let _ = <pallet_xcm::Pallet<Runtime>>::send(
 			RawOrigin::Root.into(),
-			Box::new(VersionedLocation::V4(destination)),
-			Box::new(VersionedXcm::V4(program)),
+			Box::new(VersionedLocation::from(destination)),
+			Box::new(VersionedXcm::from(program)),
 		)?;
 		Ok(())
 	}
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 21790e259f0..a9a76dbced1 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -1323,7 +1323,6 @@ impl parachains_scheduler::Config for Runtime {
 parameter_types! {
 	pub const BrokerId: u32 = BROKER_ID;
 	pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
-	pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000);
 }
 
 pub struct BrokerPot;
@@ -1347,7 +1346,6 @@ impl coretime::Config for Runtime {
 		xcm_config::ThisNetwork,
 		<Runtime as frame_system::Config>::AccountId,
 	>;
-	type MaxXcmTransactWeight = MaxXcmTransactWeight;
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs
index cb5894ea51e..e5f4a0d7ca8 100644
--- a/polkadot/runtime/westend/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs
@@ -27,6 +27,7 @@ use xcm::{
 
 use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight;
 use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric;
+use xcm::latest::AssetTransferFilter;
 
 /// Types of asset supported by the westend runtime.
 pub enum AssetTypes {
@@ -113,11 +114,7 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
 	fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
 	}
-	fn transact(
-		_origin_kind: &OriginKind,
-		_require_weight_at_most: &Weight,
-		_call: &DoubleEncoded<RuntimeCall>,
-	) -> Weight {
+	fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded<RuntimeCall>) -> Weight {
 		XcmGeneric::<Runtime>::transact()
 	}
 	fn hrmp_new_channel_open_request(
@@ -166,12 +163,35 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
 	fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight {
 		assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_teleport())
 	}
+	fn initiate_transfer(
+		_dest: &Location,
+		remote_fees: &Option<AssetTransferFilter>,
+		_preserve_origin: &bool,
+		assets: &Vec<AssetTransferFilter>,
+		_xcm: &Xcm<()>,
+	) -> Weight {
+		let mut weight = if let Some(remote_fees) = remote_fees {
+			let fees = remote_fees.inner();
+			fees.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer())
+		} else {
+			Weight::zero()
+		};
+		for asset_filter in assets {
+			let assets = asset_filter.inner();
+			let extra = assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer());
+			weight = weight.saturating_add(extra);
+		}
+		weight
+	}
 	fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
 		XcmGeneric::<Runtime>::report_holding()
 	}
 	fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight {
 		XcmGeneric::<Runtime>::buy_execution()
 	}
+	fn pay_fees(_asset: &Asset) -> Weight {
+		XcmGeneric::<Runtime>::pay_fees()
+	}
 	fn refund_surplus() -> Weight {
 		XcmGeneric::<Runtime>::refund_surplus()
 	}
@@ -184,6 +204,11 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
 	fn clear_error() -> Weight {
 		XcmGeneric::<Runtime>::clear_error()
 	}
+
+	fn set_asset_claimer(_location: &Location) -> Weight {
+		XcmGeneric::<Runtime>::set_asset_claimer()
+	}
+
 	fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight {
 		XcmGeneric::<Runtime>::claim_asset()
 	}
diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
index e0c61c8e2bf..f1ce760d48c 100644
--- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::fungible`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -55,8 +55,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `3593`
-		// Minimum execution time: 31_780_000 picoseconds.
-		Weight::from_parts(32_602_000, 3593)
+		// Minimum execution time: 31_578_000 picoseconds.
+		Weight::from_parts(32_243_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -66,8 +66,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `101`
 		//  Estimated: `6196`
-		// Minimum execution time: 41_818_000 picoseconds.
-		Weight::from_parts(42_902_000, 6196)
+		// Minimum execution time: 42_320_000 picoseconds.
+		Weight::from_parts(43_036_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(2))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
@@ -85,8 +85,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `8799`
-		// Minimum execution time: 101_949_000 picoseconds.
-		Weight::from_parts(104_190_000, 8799)
+		// Minimum execution time: 101_972_000 picoseconds.
+		Weight::from_parts(104_288_000, 8799)
 			.saturating_add(T::DbWeight::get().reads(7))
 			.saturating_add(T::DbWeight::get().writes(5))
 	}
@@ -113,8 +113,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `6196`
-		// Minimum execution time: 70_123_000 picoseconds.
-		Weight::from_parts(72_564_000, 6196)
+		// Minimum execution time: 71_916_000 picoseconds.
+		Weight::from_parts(73_610_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -124,8 +124,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `103`
 		//  Estimated: `3593`
-		// Minimum execution time: 31_868_000 picoseconds.
-		Weight::from_parts(32_388_000, 3593)
+		// Minimum execution time: 31_683_000 picoseconds.
+		Weight::from_parts(32_138_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -135,8 +135,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3593`
-		// Minimum execution time: 24_532_000 picoseconds.
-		Weight::from_parts(25_166_000, 3593)
+		// Minimum execution time: 23_786_000 picoseconds.
+		Weight::from_parts(24_188_000, 3593)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -154,8 +154,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `147`
 		//  Estimated: `3612`
-		// Minimum execution time: 63_378_000 picoseconds.
-		Weight::from_parts(65_002_000, 3612)
+		// Minimum execution time: 63_986_000 picoseconds.
+		Weight::from_parts(65_356_000, 3612)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -173,9 +173,28 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `147`
 		//  Estimated: `3612`
-		// Minimum execution time: 49_174_000 picoseconds.
-		Weight::from_parts(50_356_000, 3612)
+		// Minimum execution time: 52_672_000 picoseconds.
+		Weight::from_parts(54_623_000, 3612)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
+	/// Storage: `System::Account` (r:2 w:2)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	pub(crate) fn initiate_transfer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `250`
+		//  Estimated: `6196`
+		// Minimum execution time: 83_853_000 picoseconds.
+		Weight::from_parts(85_876_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(6))
+			.saturating_add(T::DbWeight::get().writes(4))
+	}
 }
diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 49beb85c278..2ad1cd6359a 100644
--- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -16,11 +16,11 @@
 
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
+//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
 
 // Executed Command:
 // target/production/polkadot
@@ -29,14 +29,14 @@
 // --steps=50
 // --repeat=20
 // --extrinsic=*
-// --execution=wasm
 // --wasm-execution=compiled
 // --heap-pages=4096
+// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
 // --pallet=pallet_xcm_benchmarks::generic
 // --chain=westend-dev
-// --header=./file_header.txt
-// --template=./xcm/pallet-xcm-benchmarks/template.hbs
-// --output=./runtime/westend/src/weights/xcm/
+// --header=./polkadot/file_header.txt
+// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs
+// --output=./polkadot/runtime/westend/src/weights/xcm/
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -49,126 +49,132 @@ use core::marker::PhantomData;
 /// Weight functions for `pallet_xcm_benchmarks::generic`.
 pub struct WeightInfo<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo<T> {
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:2 w:2)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_holding() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 30_790_000 picoseconds.
-		Weight::from_parts(31_265_000, 3634)
-			.saturating_add(T::DbWeight::get().reads(7))
+		//  Measured:  `351`
+		//  Estimated: `6196`
+		// Minimum execution time: 67_813_000 picoseconds.
+		Weight::from_parts(69_357_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
 	pub(crate) fn buy_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_741_000 picoseconds.
-		Weight::from_parts(2_823_000, 0)
+		// Minimum execution time: 716_000 picoseconds.
+		Weight::from_parts(780_000, 0)
 	}
-	/// Storage: XcmPallet Queries (r:1 w:0)
-	/// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured)
+	pub(crate) fn pay_fees() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 1_601_000 picoseconds.
+		Weight::from_parts(1_680_000, 0)
+	}
+	pub(crate) fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(749_000, 0)
+	}
+	/// Storage: `XcmPallet::Queries` (r:1 w:0)
+	/// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn query_response() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 10_848_000 picoseconds.
-		Weight::from_parts(11_183_000, 3634)
+		//  Measured:  `0`
+		//  Estimated: `3465`
+		// Minimum execution time: 6_574_000 picoseconds.
+		Weight::from_parts(6_790_000, 3465)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub(crate) fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 12_145_000 picoseconds.
-		Weight::from_parts(12_366_000, 0)
+		// Minimum execution time: 7_232_000 picoseconds.
+		Weight::from_parts(7_422_000, 0)
 	}
 	pub(crate) fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_837_000 picoseconds.
-		Weight::from_parts(2_939_000, 0)
+		// Minimum execution time: 1_180_000 picoseconds.
+		Weight::from_parts(1_250_000, 0)
 	}
 	pub(crate) fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_526_000 picoseconds.
-		Weight::from_parts(2_622_000, 0)
+		// Minimum execution time: 702_000 picoseconds.
+		Weight::from_parts(766_000, 0)
 	}
 	pub(crate) fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_603_000 picoseconds.
-		Weight::from_parts(2_642_000, 0)
+		// Minimum execution time: 700_000 picoseconds.
+		Weight::from_parts(757_000, 0)
 	}
 	pub(crate) fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_500_000 picoseconds.
-		Weight::from_parts(2_573_000, 0)
+		// Minimum execution time: 686_000 picoseconds.
+		Weight::from_parts(751_000, 0)
 	}
 	pub(crate) fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 3_323_000 picoseconds.
-		Weight::from_parts(3_401_000, 0)
+		// Minimum execution time: 705_000 picoseconds.
+		Weight::from_parts(765_000, 0)
 	}
 	pub(crate) fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_557_000 picoseconds.
-		Weight::from_parts(2_620_000, 0)
+		// Minimum execution time: 687_000 picoseconds.
+		Weight::from_parts(741_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:2 w:2)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_error() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 25_828_000 picoseconds.
-		Weight::from_parts(26_318_000, 3634)
-			.saturating_add(T::DbWeight::get().reads(7))
+		//  Measured:  `351`
+		//  Estimated: `6196`
+		// Minimum execution time: 65_398_000 picoseconds.
+		Weight::from_parts(67_140_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
-	/// Storage: XcmPallet AssetTraps (r:1 w:1)
-	/// Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::AssetTraps` (r:1 w:1)
+	/// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn claim_asset() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `226`
-		//  Estimated: `3691`
-		// Minimum execution time: 14_794_000 picoseconds.
-		Weight::from_parts(15_306_000, 3691)
+		//  Measured:  `23`
+		//  Estimated: `3488`
+		// Minimum execution time: 9_653_000 picoseconds.
+		Weight::from_parts(9_944_000, 3488)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -176,165 +182,151 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_534_000 picoseconds.
-		Weight::from_parts(2_574_000, 0)
+		// Minimum execution time: 698_000 picoseconds.
+		Weight::from_parts(759_000, 0)
 	}
-	/// Storage: XcmPallet VersionNotifyTargets (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured)
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1)
+	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn subscribe_version() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 32_218_000 picoseconds.
-		Weight::from_parts(32_945_000, 3634)
-			.saturating_add(T::DbWeight::get().reads(8))
-			.saturating_add(T::DbWeight::get().writes(5))
+		//  Measured:  `147`
+		//  Estimated: `3612`
+		// Minimum execution time: 31_300_000 picoseconds.
+		Weight::from_parts(31_989_000, 3612)
+			.saturating_add(T::DbWeight::get().reads(5))
+			.saturating_add(T::DbWeight::get().writes(3))
 	}
-	/// Storage: XcmPallet VersionNotifyTargets (r:0 w:1)
-	/// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1)
+	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn unsubscribe_version() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_983_000 picoseconds.
-		Weight::from_parts(5_132_000, 0)
+		// Minimum execution time: 2_863_000 picoseconds.
+		Weight::from_parts(3_027_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub(crate) fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 4_101_000 picoseconds.
-		Weight::from_parts(4_228_000, 0)
+		// Minimum execution time: 1_046_000 picoseconds.
+		Weight::from_parts(1_125_000, 0)
 	}
 	pub(crate) fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_740_000 picoseconds.
-		Weight::from_parts(2_814_000, 0)
+		// Minimum execution time: 811_000 picoseconds.
+		Weight::from_parts(871_000, 0)
 	}
 	pub(crate) fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_716_000 picoseconds.
-		Weight::from_parts(2_795_000, 0)
+		// Minimum execution time: 707_000 picoseconds.
+		Weight::from_parts(741_000, 0)
 	}
 	pub(crate) fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_550_000 picoseconds.
-		Weight::from_parts(2_601_000, 0)
+		// Minimum execution time: 687_000 picoseconds.
+		Weight::from_parts(741_000, 0)
 	}
 	pub(crate) fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_762_000 picoseconds.
-		Weight::from_parts(2_849_000, 0)
+		// Minimum execution time: 861_000 picoseconds.
+		Weight::from_parts(931_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:2 w:2)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn query_pallet() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 31_709_000 picoseconds.
-		Weight::from_parts(32_288_000, 3634)
-			.saturating_add(T::DbWeight::get().reads(7))
+		//  Measured:  `351`
+		//  Estimated: `6196`
+		// Minimum execution time: 74_622_000 picoseconds.
+		Weight::from_parts(77_059_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
 	pub(crate) fn expect_pallet() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_209_000 picoseconds.
-		Weight::from_parts(7_332_000, 0)
+		// Minimum execution time: 7_603_000 picoseconds.
+		Weight::from_parts(7_871_000, 0)
 	}
-	/// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1)
-	/// Storage: Dmp DeliveryFeeFactor (r:1 w:0)
-	/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet SupportedVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured)
-	/// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
-	/// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
-	/// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueues (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured)
-	/// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1)
-	/// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured)
+	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
+	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+	/// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:2 w:2)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
+	/// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1)
+	/// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	pub(crate) fn report_transact_status() -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `169`
-		//  Estimated: `3634`
-		// Minimum execution time: 26_161_000 picoseconds.
-		Weight::from_parts(26_605_000, 3634)
-			.saturating_add(T::DbWeight::get().reads(7))
+		//  Measured:  `351`
+		//  Estimated: `6196`
+		// Minimum execution time: 65_617_000 picoseconds.
+		Weight::from_parts(66_719_000, 6196)
+			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
 	pub(crate) fn clear_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_539_000 picoseconds.
-		Weight::from_parts(2_647_000, 0)
+		// Minimum execution time: 738_000 picoseconds.
+		Weight::from_parts(779_000, 0)
 	}
 	pub(crate) fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_494_000 picoseconds.
-		Weight::from_parts(2_588_000, 0)
+		// Minimum execution time: 688_000 picoseconds.
+		Weight::from_parts(755_000, 0)
 	}
 	pub(crate) fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_510_000 picoseconds.
-		Weight::from_parts(2_590_000, 0)
+		// Minimum execution time: 684_000 picoseconds.
+		Weight::from_parts(722_000, 0)
 	}
 	pub(crate) fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_491_000 picoseconds.
-		Weight::from_parts(2_546_000, 0)
+		// Minimum execution time: 694_000 picoseconds.
+		Weight::from_parts(738_000, 0)
 	}
 	pub(crate) fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_696_000 picoseconds.
-		Weight::from_parts(2_816_000, 0)
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
 	}
 }
diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs
index d75083929a0..f8bb2676de3 100644
--- a/polkadot/runtime/westend/src/xcm_config.rs
+++ b/polkadot/runtime/westend/src/xcm_config.rs
@@ -36,7 +36,7 @@ use sp_core::ConstU32;
 use westend_runtime_constants::{
 	currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX,
 };
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH};
 use xcm_builder::{
 	AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
 	AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
@@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor;
 parameter_types! {
 	pub const TokenLocation: Location = Here.into_location();
 	pub const RootLocation: Location = Location::here();
-	pub const ThisNetwork: NetworkId = Westend;
+	pub const ThisNetwork: NetworkId = ByGenesis(WESTEND_GENESIS_HASH);
 	pub UniversalLocation: InteriorLocation = [GlobalConsensus(ThisNetwork::get())].into();
 	pub CheckAccount: AccountId = XcmPallet::check_account();
 	pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local);
diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml
index 862f5557a01..86c7067ad6f 100644
--- a/polkadot/xcm/Cargo.toml
+++ b/polkadot/xcm/Cargo.toml
@@ -23,11 +23,12 @@ serde = { features = ["alloc", "derive", "rc"], workspace = true }
 schemars = { default-features = true, optional = true, workspace = true }
 xcm-procedural = { workspace = true, default-features = true }
 environmental = { workspace = true }
+hex-literal = { workspace = true, default-features = true }
+frame-support = { workspace = true }
 
 [dev-dependencies]
 sp-io = { workspace = true, default-features = true }
 hex = { workspace = true, default-features = true }
-hex-literal = { workspace = true, default-features = true }
 
 [features]
 default = ["std"]
@@ -36,6 +37,7 @@ std = [
 	"bounded-collections/std",
 	"codec/std",
 	"environmental/std",
+	"frame-support/std",
 	"log/std",
 	"scale-info/std",
 	"serde/std",
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs
index f8a1826b8ab..0180354458c 100644
--- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs
@@ -21,7 +21,7 @@ use frame::{
 	runtime::prelude::*,
 	traits::{Everything, Nothing},
 };
-use xcm::v4::prelude::*;
+use xcm::latest::prelude::*;
 use xcm_builder::{
 	AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
 	FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete,
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs
index 686f86b37b7..cd8701dbbed 100644
--- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs
@@ -23,7 +23,7 @@ use frame::{
 	traits::{IdentityLookup, ProcessMessage, ProcessMessageError},
 };
 use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId};
-use xcm::v4::prelude::*;
+use xcm::latest::prelude::*;
 
 mod xcm_config;
 pub use xcm_config::LocationToAccountId;
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs
index e7b602df733..06b00c39e8a 100644
--- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs
@@ -21,7 +21,7 @@ use frame::{
 	runtime::prelude::*,
 	traits::{Everything, Nothing},
 };
-use xcm::v4::prelude::*;
+use xcm::latest::prelude::*;
 use xcm_builder::{
 	AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
 	FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete,
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs
index 792cf6149e7..b7fdaa34ec8 100644
--- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs
@@ -65,9 +65,9 @@ fn reserve_asset_transfers_work() {
 		let assets: Assets = (Here, 50u128 * CENTS as u128).into();
 		assert_ok!(relay_chain::XcmPallet::transfer_assets(
 			relay_chain::RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedLocation::V4(destination.clone())),
-			Box::new(VersionedLocation::V4(beneficiary)),
-			Box::new(VersionedAssets::V4(assets)),
+			Box::new(VersionedLocation::from(destination.clone())),
+			Box::new(VersionedLocation::from(beneficiary)),
+			Box::new(VersionedAssets::from(assets)),
 			0,
 			WeightLimit::Unlimited,
 		));
@@ -101,9 +101,9 @@ fn reserve_asset_transfers_work() {
 		let assets: Assets = (Parent, 25u128 * CENTS as u128).into();
 		assert_ok!(parachain::XcmPallet::transfer_assets(
 			parachain::RuntimeOrigin::signed(BOB),
-			Box::new(VersionedLocation::V4(destination)),
-			Box::new(VersionedLocation::V4(beneficiary)),
-			Box::new(VersionedAssets::V4(assets)),
+			Box::new(VersionedLocation::from(destination)),
+			Box::new(VersionedLocation::from(beneficiary)),
+			Box::new(VersionedAssets::from(assets)),
 			0,
 			WeightLimit::Unlimited,
 		));
diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs
index 6ce49074a6e..303ff9493f7 100644
--- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs
@@ -24,7 +24,7 @@ use frame_support::{
 	weights::Weight,
 };
 use sp_runtime::traits::{Bounded, Zero};
-use xcm::latest::{prelude::*, MAX_ITEMS_IN_ASSETS};
+use xcm::latest::{prelude::*, AssetTransferFilter, MAX_ITEMS_IN_ASSETS};
 use xcm_executor::traits::{ConvertLocation, FeeReason, TransactAsset};
 
 benchmarks_instance_pallet! {
@@ -299,6 +299,33 @@ benchmarks_instance_pallet! {
 		}
 	}
 
+	initiate_transfer {
+		let (sender_account, sender_location) = account_and_location::<T>(1);
+		let asset = T::get_asset();
+		let mut holding = T::worst_case_holding(1);
+		let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
+
+		// Add our asset to the holding.
+		holding.push(asset.clone());
+
+		let mut executor = new_executor::<T>(sender_location);
+		executor.set_holding(holding.into());
+		let instruction = Instruction::<XcmCallOf<T>>::InitiateTransfer {
+			destination: T::valid_destination()?,
+			// ReserveDeposit is the most expensive filter.
+			remote_fees: Some(AssetTransferFilter::ReserveDeposit(asset.clone().into())),
+			// It's more expensive if we reanchor the origin.
+			preserve_origin: true,
+			assets: vec![AssetTransferFilter::ReserveDeposit(asset.into())],
+			remote_xcm: Xcm::new(),
+		};
+		let xcm = Xcm(vec![instruction]);
+	}: {
+		executor.bench_process(xcm)?;
+	} verify {
+		assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
+	}
+
 	impl_benchmark_test_suite!(
 		Pallet,
 		crate::fungible::mock::new_test_ext(),
diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
index f1ec3f604d7..0d80ef89a1c 100644
--- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
@@ -19,7 +19,7 @@ use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf};
 use alloc::{vec, vec::Vec};
 use codec::Encode;
 use frame_benchmarking::{benchmarks, BenchmarkError};
-use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect};
+use frame_support::traits::fungible::Inspect;
 use xcm::{
 	latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS},
 	DoubleEncoded,
@@ -98,6 +98,36 @@ benchmarks! {
 
 	}
 
+	pay_fees {
+		let holding = T::worst_case_holding(0).into();
+
+		let mut executor = new_executor::<T>(Default::default());
+		executor.set_holding(holding);
+		// Set some weight to be paid for.
+		executor.set_message_weight(Weight::from_parts(100_000_000, 100_000));
+
+		let fee_asset: Asset = T::fee_asset().unwrap();
+
+		let instruction = Instruction::<XcmCallOf<T>>::PayFees { asset: fee_asset };
+
+		let xcm = Xcm(vec![instruction]);
+	} : {
+		executor.bench_process(xcm)?;
+	} verify {}
+
+	set_asset_claimer {
+		let mut executor = new_executor::<T>(Default::default());
+		let (_, sender_location) = account_and_location::<T>(1);
+
+		let instruction = Instruction::SetAssetClaimer{ location:sender_location.clone() };
+
+		let xcm = Xcm(vec![instruction]);
+	}: {
+		executor.bench_process(xcm)?;
+	} verify {
+		assert_eq!(executor.asset_claimer(), Some(sender_location.clone()));
+	}
+
 	query_response {
 		let mut executor = new_executor::<T>(Default::default());
 		let (query_id, response) = T::worst_case_response();
@@ -121,7 +151,6 @@ benchmarks! {
 
 		let instruction = Instruction::Transact {
 			origin_kind: OriginKind::SovereignAccount,
-			require_weight_at_most: noop_call.get_dispatch_info().call_weight,
 			call: double_encoded_noop_call,
 		};
 		let xcm = Xcm(vec![instruction]);
diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs
index 404b9358d4d..e493d4838f5 100644
--- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs
@@ -382,8 +382,8 @@ benchmarks! {
 			asset.clone().into(),
 			&XcmContext { origin: None, message_id: [0u8; 32], topic: None }
 		);
-		let versioned_assets = VersionedAssets::V4(asset.into());
-	}: _<RuntimeOrigin<T>>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::V4(claim_location)))
+		let versioned_assets = VersionedAssets::from(Assets::from(asset));
+	}: _<RuntimeOrigin<T>>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::from(claim_location)))
 
 	impl_benchmark_test_suite!(
 		Pallet,
diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs
index 9b8f735b478..4a97546b38d 100644
--- a/polkadot/xcm/pallet-xcm/src/lib.rs
+++ b/polkadot/xcm/pallet-xcm/src/lib.rs
@@ -2536,7 +2536,7 @@ impl<T: Config> Pallet<T> {
 	///
 	/// Returns execution result, events, and any forwarded XCMs to other locations.
 	/// Meant to be used in the `xcm_runtime_apis::dry_run::DryRunApi` runtime API.
-	pub fn dry_run_xcm<Runtime, Router, RuntimeCall, XcmConfig>(
+	pub fn dry_run_xcm<Runtime, Router, RuntimeCall: Decode + GetDispatchInfo, XcmConfig>(
 		origin_location: VersionedLocation,
 		xcm: VersionedXcm<RuntimeCall>,
 	) -> Result<XcmDryRunEffects<<Runtime as frame_system::Config>::RuntimeEvent>, XcmDryRunApiError>
@@ -3067,7 +3067,7 @@ impl<T: Config> xcm_executor::traits::AssetLock for Pallet<T> {
 }
 
 impl<T: Config> WrapVersion for Pallet<T> {
-	fn wrap_version<RuntimeCall>(
+	fn wrap_version<RuntimeCall: Decode + GetDispatchInfo>(
 		dest: &Location,
 		xcm: impl Into<VersionedXcm<RuntimeCall>>,
 	) -> Result<VersionedXcm<RuntimeCall>, ()> {
diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs
index e98a8f8d2ce..350530f7711 100644
--- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs
+++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs
@@ -482,14 +482,14 @@ fn claim_assets_works() {
 		// Even though assets are trapped, the extrinsic returns success.
 		assert_ok!(XcmPallet::execute(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedXcm::V4(trapping_program)),
+			Box::new(VersionedXcm::from(trapping_program)),
 			BaseXcmWeight::get() * 2,
 		));
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
 
 		// Expected `AssetsTrapped` event info.
 		let source: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
-		let versioned_assets = VersionedAssets::V4(Assets::from((Here, SEND_AMOUNT)));
+		let versioned_assets = VersionedAssets::from(Assets::from((Here, SEND_AMOUNT)));
 		let hash = BlakeTwo256::hash_of(&(source.clone(), versioned_assets.clone()));
 
 		// Assets were indeed trapped.
@@ -512,10 +512,11 @@ fn claim_assets_works() {
 		// Now claim them with the extrinsic.
 		assert_ok!(XcmPallet::claim_assets(
 			RuntimeOrigin::signed(ALICE),
-			Box::new(VersionedAssets::V4((Here, SEND_AMOUNT).into())),
-			Box::new(VersionedLocation::V4(
-				AccountId32 { network: None, id: ALICE.clone().into() }.into()
-			)),
+			Box::new(VersionedAssets::from(Assets::from((Here, SEND_AMOUNT)))),
+			Box::new(VersionedLocation::from(Location::from(AccountId32 {
+				network: None,
+				id: ALICE.clone().into()
+			}))),
 		));
 		assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
 		assert_eq!(AssetTraps::<Test>::iter().collect::<Vec<_>>(), vec![]);
diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs
index 09ead1389d1..b65290332af 100644
--- a/polkadot/xcm/procedural/src/builder_pattern.rs
+++ b/polkadot/xcm/procedural/src/builder_pattern.rs
@@ -160,13 +160,16 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStre
 			};
 			let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") };
 			let inner_ident: Ident = syn::parse2(list.tokens.clone()).map_err(|_| {
-				Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`")
+				Error::new_spanned(
+					&builder_attr,
+					"Expected `builder(loads_holding)` or `builder(pays_fees)`",
+				)
 			})?;
 			let ident_to_match: Ident = syn::parse_quote!(loads_holding);
 			if inner_ident == ident_to_match {
 				Ok(Some(variant))
 			} else {
-				Err(Error::new_spanned(&builder_attr, "Expected `builder(loads_holding)`"))
+				Ok(None) // Must have been `pays_fees` instead.
 			}
 		})
 		.collect::<Result<Vec<_>>>()?;
@@ -260,50 +263,75 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result<TokenStre
 		.collect::<std::result::Result<Vec<_>, _>>()?;
 
 	// Then we require fees to be paid
-	let buy_execution_method = data_enum
+	let pay_fees_variants = data_enum
 		.variants
 		.iter()
-		.find(|variant| variant.ident == "BuyExecution")
-		.map_or(
-			Err(Error::new_spanned(&data_enum.variants, "No BuyExecution instruction")),
-			|variant| {
-				let variant_name = &variant.ident;
-				let method_name_string = &variant_name.to_string().to_snake_case();
-				let method_name = syn::Ident::new(method_name_string, variant_name.span());
-				let docs = get_doc_comments(variant);
-				let fields = match &variant.fields {
-					Fields::Named(fields) => {
-						let arg_names: Vec<_> =
-							fields.named.iter().map(|field| &field.ident).collect();
-						let arg_types: Vec<_> =
-							fields.named.iter().map(|field| &field.ty).collect();
-						quote! {
-							#(#docs)*
-							pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder<Call, AnythingGoes> {
-								let mut new_instructions = self.instructions;
-								#(let #arg_names = #arg_names.into();)*
-								new_instructions.push(#name::<Call>::#variant_name { #(#arg_names),* });
-								XcmBuilder {
-									instructions: new_instructions,
-									state: core::marker::PhantomData,
-								}
+		.map(|variant| {
+			let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta {
+				Meta::List(ref list) => list.path.is_ident("builder"),
+				_ => false,
+			});
+			let builder_attr = match maybe_builder_attr {
+				Some(builder) => builder.clone(),
+				None => return Ok(None), /* It's not going to be an instruction that pays fees */
+			};
+			let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") };
+			let inner_ident: Ident = syn::parse2(list.tokens.clone()).map_err(|_| {
+				Error::new_spanned(
+					&builder_attr,
+					"Expected `builder(loads_holding)` or `builder(pays_fees)`",
+				)
+			})?;
+			let ident_to_match: Ident = syn::parse_quote!(pays_fees);
+			if inner_ident == ident_to_match {
+				Ok(Some(variant))
+			} else {
+				Ok(None) // Must have been `loads_holding` instead.
+			}
+		})
+		.collect::<Result<Vec<_>>>()?;
+
+	let pay_fees_methods = pay_fees_variants
+		.into_iter()
+		.flatten()
+		.map(|variant| {
+			let variant_name = &variant.ident;
+			let method_name_string = &variant_name.to_string().to_snake_case();
+			let method_name = syn::Ident::new(method_name_string, variant_name.span());
+			let docs = get_doc_comments(variant);
+			let fields = match &variant.fields {
+				Fields::Named(fields) => {
+					let arg_names: Vec<_> =
+						fields.named.iter().map(|field| &field.ident).collect();
+					let arg_types: Vec<_> =
+						fields.named.iter().map(|field| &field.ty).collect();
+					quote! {
+						#(#docs)*
+						pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder<Call, AnythingGoes> {
+							let mut new_instructions = self.instructions;
+							#(let #arg_names = #arg_names.into();)*
+							new_instructions.push(#name::<Call>::#variant_name { #(#arg_names),* });
+							XcmBuilder {
+								instructions: new_instructions,
+								state: core::marker::PhantomData,
 							}
 						}
-					},
-					_ =>
-						return Err(Error::new_spanned(
-							variant,
-							"BuyExecution should have named fields",
-						)),
-				};
-				Ok(fields)
-			},
-		)?;
+					}
+				},
+				_ =>
+					return Err(Error::new_spanned(
+						variant,
+						"Both BuyExecution and PayFees have named fields",
+					)),
+			};
+			Ok(fields)
+		})
+		.collect::<Result<Vec<_>>>()?;
 
 	let second_impl = quote! {
 		impl<Call> XcmBuilder<Call, LoadedHolding> {
 			#(#allowed_after_load_holding_methods)*
-			#buy_execution_method
+			#(#pay_fees_methods)*
 		}
 	};
 
diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs
index 4980d84d328..9971fdceb69 100644
--- a/polkadot/xcm/procedural/src/lib.rs
+++ b/polkadot/xcm/procedural/src/lib.rs
@@ -20,25 +20,11 @@ use proc_macro::TokenStream;
 use syn::{parse_macro_input, DeriveInput};
 
 mod builder_pattern;
-mod v2;
 mod v3;
 mod v4;
+mod v5;
 mod weight_info;
 
-#[proc_macro]
-pub fn impl_conversion_functions_for_multilocation_v2(input: TokenStream) -> TokenStream {
-	v2::multilocation::generate_conversion_functions(input)
-		.unwrap_or_else(syn::Error::into_compile_error)
-		.into()
-}
-
-#[proc_macro]
-pub fn impl_conversion_functions_for_junctions_v2(input: TokenStream) -> TokenStream {
-	v2::junctions::generate_conversion_functions(input)
-		.unwrap_or_else(syn::Error::into_compile_error)
-		.into()
-}
-
 #[proc_macro_derive(XcmWeightInfoTrait)]
 pub fn derive_xcm_weight_info(item: TokenStream) -> TokenStream {
 	weight_info::derive(item)
@@ -72,6 +58,20 @@ pub fn impl_conversion_functions_for_junctions_v4(input: TokenStream) -> TokenSt
 		.into()
 }
 
+#[proc_macro]
+pub fn impl_conversion_functions_for_junctions_v5(input: TokenStream) -> TokenStream {
+	v5::junctions::generate_conversion_functions(input)
+		.unwrap_or_else(syn::Error::into_compile_error)
+		.into()
+}
+
+#[proc_macro]
+pub fn impl_conversion_functions_for_location_v5(input: TokenStream) -> TokenStream {
+	v5::location::generate_conversion_functions(input)
+		.unwrap_or_else(syn::Error::into_compile_error)
+		.into()
+}
+
 /// This is called on the `Instruction` enum, not on the `Xcm` struct,
 /// and allows for the following syntax for building XCMs:
 /// let message = Xcm::builder()
diff --git a/polkadot/xcm/procedural/src/v2.rs b/polkadot/xcm/procedural/src/v2.rs
deleted file mode 100644
index 6878f7755cc..00000000000
--- a/polkadot/xcm/procedural/src/v2.rs
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-use proc_macro2::{Span, TokenStream};
-use quote::{format_ident, quote};
-use syn::{Result, Token};
-
-pub mod multilocation {
-	use super::*;
-
-	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
-		if !input.is_empty() {
-			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
-		}
-
-		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
-		let from_tuples = generate_conversion_from_tuples(8);
-		let from_v3 = generate_conversion_from_v3();
-
-		Ok(quote! {
-			#from_tuples
-			#from_v3
-		})
-	}
-
-	fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream {
-		let mut from_tuples = (0..8usize)
-			.map(|num_junctions| {
-				let junctions =
-					(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
-				let idents =
-					(0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
-				let variant = &format_ident!("X{}", num_junctions + 1);
-				let array_size = num_junctions + 1;
-
-				let mut from_tuple = quote! {
-					impl From<( #(#junctions,)* )> for MultiLocation {
-						fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
-							MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
-						}
-					}
-
-					impl From<(u8, #(#junctions),*)> for MultiLocation {
-						fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self {
-							MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
-						}
-					}
-
-					impl From<(Ancestor, #(#junctions),*)> for MultiLocation {
-						fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self {
-							MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
-						}
-					}
-
-					impl From<[Junction; #array_size]> for MultiLocation {
-						fn from(j: [Junction; #array_size]) -> Self {
-							let [#(#idents),*] = j;
-							MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
-						}
-					}
-				};
-
-				let from_parent_tuples = (1..=max_parents).map(|cur_parents| {
-					let parents =
-						(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
-					let underscores =
-						(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
-
-					quote! {
-						impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation {
-							fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self {
-								MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) }
-							}
-						}
-					}
-				});
-
-				from_tuple.extend(from_parent_tuples);
-				from_tuple
-			})
-			.collect::<TokenStream>();
-
-		let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| {
-			let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
-			let underscores =
-				(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
-
-			quote! {
-				impl From<( #(#parents,)* Junctions )> for MultiLocation {
-					fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
-						MultiLocation { parents: #cur_parents, interior: junctions }
-					}
-				}
-			}
-		});
-		from_tuples.extend(from_parent_junctions_tuples);
-
-		quote! {
-			impl From<Junctions> for MultiLocation {
-				fn from(junctions: Junctions) -> Self {
-					MultiLocation { parents: 0, interior: junctions }
-				}
-			}
-
-			impl From<(u8, Junctions)> for MultiLocation {
-				fn from((parents, interior): (u8, Junctions)) -> Self {
-					MultiLocation { parents, interior }
-				}
-			}
-
-			impl From<(Ancestor, Junctions)> for MultiLocation {
-				fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
-					MultiLocation { parents, interior }
-				}
-			}
-
-			impl From<()> for MultiLocation {
-				fn from(_: ()) -> Self {
-					MultiLocation { parents: 0, interior: Junctions::Here }
-				}
-			}
-
-			impl From<(u8,)> for MultiLocation {
-				fn from((parents,): (u8,)) -> Self {
-					MultiLocation { parents, interior: Junctions::Here }
-				}
-			}
-
-			impl From<Junction> for MultiLocation {
-				fn from(x: Junction) -> Self {
-					MultiLocation { parents: 0, interior: Junctions::X1(x) }
-				}
-			}
-
-			impl From<[Junction; 0]> for MultiLocation {
-				fn from(_: [Junction; 0]) -> Self {
-					MultiLocation { parents: 0, interior: Junctions::Here }
-				}
-			}
-
-			#from_tuples
-		}
-	}
-
-	fn generate_conversion_from_v3() -> TokenStream {
-		let match_variants = (0..8u8)
-			.map(|cur_num| {
-				let num_ancestors = cur_num + 1;
-				let variant = format_ident!("X{}", num_ancestors);
-				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
-
-				quote! {
-					crate::v3::Junctions::#variant( #(#idents),* ) =>
-						#variant( #( core::convert::TryInto::try_into(#idents)? ),* ),
-				}
-			})
-			.collect::<TokenStream>();
-
-		quote! {
-			impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
-				type Error = ();
-				fn try_from(mut new: crate::v3::Junctions) -> core::result::Result<Self, ()> {
-					use Junctions::*;
-					Ok(match new {
-						crate::v3::Junctions::Here => Here,
-						#match_variants
-					})
-				}
-			}
-		}
-	}
-}
-
-pub mod junctions {
-	use super::*;
-
-	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
-		if !input.is_empty() {
-			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
-		}
-
-		let from_slice_syntax = generate_conversion_from_slice_syntax();
-
-		Ok(quote! {
-			#from_slice_syntax
-		})
-	}
-
-	fn generate_conversion_from_slice_syntax() -> TokenStream {
-		quote! {
-			macro_rules! impl_junction {
-				($count:expr, $variant:ident, ($($index:literal),+)) => {
-					/// Additional helper for building junctions
-					/// Useful for converting to future XCM versions
-					impl From<[Junction; $count]> for Junctions {
-						fn from(junctions: [Junction; $count]) -> Self {
-							Self::$variant($(junctions[$index].clone()),*)
-						}
-					}
-				};
-			}
-
-			impl_junction!(1, X1, (0));
-			impl_junction!(2, X2, (0, 1));
-			impl_junction!(3, X3, (0, 1, 2));
-			impl_junction!(4, X4, (0, 1, 2, 3));
-			impl_junction!(5, X5, (0, 1, 2, 3, 4));
-			impl_junction!(6, X6, (0, 1, 2, 3, 4, 5));
-			impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6));
-			impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7));
-		}
-	}
-}
diff --git a/polkadot/xcm/procedural/src/v3.rs b/polkadot/xcm/procedural/src/v3.rs
index f0556d5a8d4..1292b56277d 100644
--- a/polkadot/xcm/procedural/src/v3.rs
+++ b/polkadot/xcm/procedural/src/v3.rs
@@ -127,12 +127,10 @@ pub mod junctions {
 		}
 
 		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
-		let from_v2 = generate_conversion_from_v2(MAX_JUNCTIONS);
 		let from_v4 = generate_conversion_from_v4();
 		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
 
 		Ok(quote! {
-			#from_v2
 			#from_v4
 			#from_tuples
 		})
@@ -194,32 +192,4 @@ pub mod junctions {
 			}
 		}
 	}
-
-	fn generate_conversion_from_v2(max_junctions: usize) -> TokenStream {
-		let match_variants = (0..max_junctions)
-			.map(|cur_num| {
-				let num_ancestors = cur_num + 1;
-				let variant = format_ident!("X{}", num_ancestors);
-				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
-
-				quote! {
-					crate::v2::Junctions::#variant( #(#idents),* ) =>
-						#variant( #( core::convert::TryInto::try_into(#idents)? ),* ),
-				}
-			})
-			.collect::<TokenStream>();
-
-		quote! {
-			impl core::convert::TryFrom<crate::v2::Junctions> for Junctions {
-				type Error = ();
-				fn try_from(mut old: crate::v2::Junctions) -> core::result::Result<Self, ()> {
-					use Junctions::*;
-					Ok(match old {
-						crate::v2::Junctions::Here => Here,
-						#match_variants
-					})
-				}
-			}
-		}
-	}
 }
diff --git a/polkadot/xcm/procedural/src/v4.rs b/polkadot/xcm/procedural/src/v4.rs
index 5f5e10d3081..9bc2f094d02 100644
--- a/polkadot/xcm/procedural/src/v4.rs
+++ b/polkadot/xcm/procedural/src/v4.rs
@@ -132,10 +132,12 @@ pub mod junctions {
 
 		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
 		let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS);
+		let from_v5 = generate_conversion_from_v5(MAX_JUNCTIONS);
 		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
 
 		Ok(quote! {
 			#from_v3
+			#from_v5
 			#from_tuples
 		})
 	}
@@ -193,4 +195,43 @@ pub mod junctions {
 			}
 		}
 	}
+
+	fn generate_conversion_from_v5(max_junctions: usize) -> TokenStream {
+		let match_variants = (0..max_junctions)
+			.map(|current_number| {
+				let number_ancestors = current_number + 1;
+				let variant = format_ident!("X{}", number_ancestors);
+				let idents =
+					(0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+				let convert = idents
+					.iter()
+					.map(|ident| {
+						quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
+					})
+					.collect::<Vec<_>>();
+
+				quote! {
+					crate::v5::Junctions::#variant( junctions ) => {
+						let [#(#idents),*] = &*junctions;
+						#(#convert);*
+						[#(#idents),*].into()
+					},
+				}
+			})
+			.collect::<TokenStream>();
+
+		quote! {
+			impl core::convert::TryFrom<crate::v5::Junctions> for Junctions {
+				type Error = ();
+
+				fn try_from(mut new: crate::v5::Junctions) -> core::result::Result<Self, Self::Error> {
+					use Junctions::*;
+					Ok(match new {
+						crate::v5::Junctions::Here => Here,
+						#match_variants
+					})
+				}
+			}
+		}
+	}
 }
diff --git a/polkadot/xcm/procedural/src/v5.rs b/polkadot/xcm/procedural/src/v5.rs
new file mode 100644
index 00000000000..895a323c173
--- /dev/null
+++ b/polkadot/xcm/procedural/src/v5.rs
@@ -0,0 +1,198 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote};
+use syn::{Result, Token};
+
+const MAX_JUNCTIONS: usize = 8;
+
+pub mod location {
+	use super::*;
+
+	/// Generates conversion functions from other types to the `Location` type:
+	/// - [PalletInstance(50), GeneralIndex(1984)].into()
+	/// - (Parent, Parachain(1000), AccountId32 { .. }).into()
+	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
+		if !input.is_empty() {
+			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
+		}
+
+		let from_tuples = generate_conversion_from_tuples(8, 8);
+
+		Ok(quote! {
+			#from_tuples
+		})
+	}
+
+	fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
+		let mut from_tuples = (0..=max_junctions)
+			.map(|num_junctions| {
+				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
+				let idents =
+					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+				let array_size = num_junctions;
+				let interior = if num_junctions == 0 {
+					quote!(Junctions::Here)
+				} else {
+					let variant = format_ident!("X{}", num_junctions);
+					quote! {
+						Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
+					}
+				};
+
+				let mut from_tuple = quote! {
+					impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
+						fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
+							Location { parents, interior: #interior }
+						}
+					}
+
+					impl From<[Junction; #array_size]> for Location {
+						fn from(j: [Junction; #array_size]) -> Self {
+							let [#(#idents),*] = j;
+							Location { parents: 0, interior: #interior }
+						}
+					}
+				};
+
+				let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
+					let parents =
+						(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
+					let underscores =
+						(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
+
+					quote! {
+						impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
+							fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
+								Self { parents: #cur_parents as u8, interior: #interior }
+							}
+						}
+					}
+				});
+
+				from_tuple.extend(from_parent_tuples);
+				from_tuple
+			})
+			.collect::<TokenStream>();
+
+		let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
+			let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
+			let underscores =
+				(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
+
+			quote! {
+				impl From<( #(#parents,)* Junctions )> for Location {
+					fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
+						Location { parents: #cur_parents as u8, interior: junctions }
+					}
+				}
+			}
+		});
+		from_tuples.extend(from_parent_junctions_tuples);
+
+		quote! {
+			impl From<(Ancestor, Junctions)> for Location {
+				fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
+					Location { parents, interior }
+				}
+			}
+
+			impl From<Junction> for Location {
+				fn from(x: Junction) -> Self {
+					Location { parents: 0, interior: [x].into() }
+				}
+			}
+
+			#from_tuples
+		}
+	}
+}
+
+pub mod junctions {
+	use super::*;
+
+	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
+		if !input.is_empty() {
+			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
+		}
+
+		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
+		let from_v4 = generate_conversion_from_v4(MAX_JUNCTIONS);
+		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
+
+		Ok(quote! {
+			#from_v4
+			#from_tuples
+		})
+	}
+
+	fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
+		(1..=max_junctions)
+			.map(|num_junctions| {
+				let idents =
+					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
+
+				quote! {
+					impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
+						fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
+							[#(#idents .into()),*].into()
+						}
+					}
+				}
+			})
+			.collect()
+	}
+
+	fn generate_conversion_from_v4(max_junctions: usize) -> TokenStream {
+		let match_variants = (0..max_junctions)
+			.map(|cur_num| {
+				let num_ancestors = cur_num + 1;
+				let variant = format_ident!("X{}", num_ancestors);
+				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+				let convert = idents
+					.iter()
+					.enumerate()
+					.map(|(index, ident)| {
+						quote! { let #ident = core::convert::TryInto::try_into(slice[#index].clone())?; }
+					})
+					.collect::<Vec<_>>();
+
+				quote! {
+					crate::v4::Junctions::#variant( arc ) => {
+						let slice = &arc[..];
+						#(#convert);*;
+						let junctions: Junctions = [#(#idents),*].into();
+						junctions
+					},
+				}
+			})
+			.collect::<TokenStream>();
+
+		quote! {
+			impl core::convert::TryFrom<crate::v4::Junctions> for Junctions {
+				type Error = ();
+				fn try_from(mut old: crate::v4::Junctions) -> core::result::Result<Self, ()> {
+					Ok(match old {
+					 crate::v4::Junctions::Here => Junctions::Here,
+					 #match_variants
+					})
+				}
+			}
+		}
+	}
+}
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr
index 978faf2e868..e4038dc25ae 100644
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr
+++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr
@@ -1,4 +1,4 @@
-error: Expected `builder(loads_holding)`
+error: Expected `builder(loads_holding)` or `builder(pays_fees)`
   --> tests/ui/builder_pattern/badly_formatted_attribute.rs:25:5
    |
 25 |     #[builder(funds_holding = 2)]
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs
deleted file mode 100644
index dc5c679a96e..00000000000
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Test error when the `BuyExecution` instruction doesn't take named fields.
-
-use xcm_procedural::Builder;
-
-struct Xcm<Call>(pub Vec<Instruction<Call>>);
-
-#[derive(Builder)]
-enum Instruction<Call> {
-    BuyExecution(u128),
-    UnpaidExecution { weight_limit: (u32, u32) },
-    Transact { call: Call },
-}
-
-fn main() {}
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr
deleted file mode 100644
index dc8246770ba..00000000000
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr
+++ /dev/null
@@ -1,5 +0,0 @@
-error: BuyExecution should have named fields
-  --> tests/ui/builder_pattern/buy_execution_named_fields.rs:25:5
-   |
-25 |     BuyExecution(u128),
-   |     ^^^^^^^^^^^^^^^^^^
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr
deleted file mode 100644
index d8798c8223f..00000000000
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-error: No BuyExecution instruction
-  --> tests/ui/builder_pattern/no_buy_execution.rs:25:5
-   |
-25 | /     UnpaidExecution { weight_limit: (u32, u32) },
-26 | |     Transact { call: Call },
-   | |____________________________^
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs
deleted file mode 100644
index 5808ec571ce..00000000000
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Test error when using wrong attribute.
-
-use xcm_procedural::Builder;
-
-struct Xcm<Call>(pub Vec<Instruction<Call>>);
-
-#[derive(Builder)]
-enum Instruction<Call> {
-    #[builder(funds_holding)]
-    WithdrawAsset(u128),
-    BuyExecution { fees: u128 },
-    UnpaidExecution { weight_limit: (u32, u32) },
-    Transact { call: Call },
-}
-
-fn main() {}
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr
deleted file mode 100644
index 1ff9d185136..00000000000
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr
+++ /dev/null
@@ -1,5 +0,0 @@
-error: Expected `builder(loads_holding)`
-  --> tests/ui/builder_pattern/unexpected_attribute.rs:25:5
-   |
-25 |     #[builder(funds_holding)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs
index 0b916c87f54..a41a8e797b0 100644
--- a/polkadot/xcm/src/lib.rs
+++ b/polkadot/xcm/src/lib.rs
@@ -21,28 +21,24 @@
 //
 // Hence, `no_std` rather than sp-runtime.
 #![cfg_attr(not(feature = "std"), no_std)]
-// Because of XCMv2.
-#![allow(deprecated)]
 
 extern crate alloc;
 
 use codec::{Decode, DecodeLimit, Encode, Error as CodecError, Input, MaxEncodedLen};
 use derivative::Derivative;
+use frame_support::dispatch::GetDispatchInfo;
 use scale_info::TypeInfo;
 
-#[deprecated(
-	note = "XCMv2 will be removed once XCMv5 is released. Please use XCMv3 or XCMv4 instead."
-)]
-pub mod v2;
 pub mod v3;
 pub mod v4;
+pub mod v5;
 
 pub mod lts {
 	pub use super::v4::*;
 }
 
 pub mod latest {
-	pub use super::v4::*;
+	pub use super::v5::*;
 }
 
 mod double_encoded;
@@ -81,12 +77,16 @@ pub trait TryAs<T> {
 	fn try_as(&self) -> Result<&T, ()>;
 }
 
+// Macro that generated versioned wrapper types.
+// NOTE: converting a v4 type into a versioned type will make it v5.
 macro_rules! versioned_type {
 	($(#[$attr:meta])* pub enum $n:ident {
 		$(#[$index3:meta])+
 		V3($v3:ty),
 		$(#[$index4:meta])+
 		V4($v4:ty),
+		$(#[$index5:meta])+
+		V5($v5:ty),
 	}) => {
 		#[derive(Derivative, Encode, Decode, TypeInfo)]
 		#[derivative(
@@ -104,6 +104,8 @@ macro_rules! versioned_type {
 			V3($v3),
 			$(#[$index4])*
 			V4($v4),
+			$(#[$index5])*
+			V5($v5),
 		}
 		impl $n {
 			pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
@@ -126,11 +128,20 @@ macro_rules! versioned_type {
 				}
 			}
 		}
+		impl TryAs<$v5> for $n {
+			fn try_as(&self) -> Result<&$v5, ()> {
+				match &self {
+					Self::V5(ref x) => Ok(x),
+					_ => Err(()),
+				}
+			}
+		}
 		impl IntoVersion for $n {
 			fn into_version(self, n: Version) -> Result<Self, ()> {
 				Ok(match n {
 					3 => Self::V3(self.try_into()?),
 					4 => Self::V4(self.try_into()?),
+					5 => Self::V5(self.try_into()?),
 					_ => return Err(()),
 				})
 			}
@@ -140,9 +151,9 @@ macro_rules! versioned_type {
 				$n::V3(x.into())
 			}
 		}
-		impl From<$v4> for $n {
-			fn from(x: $v4) -> Self {
-				$n::V4(x.into())
+		impl<T: Into<$v5>> From<T> for $n {
+			fn from(x: T) -> Self {
+				$n::V5(x.into())
 			}
 		}
 		impl TryFrom<$n> for $v3 {
@@ -151,7 +162,11 @@ macro_rules! versioned_type {
 				use $n::*;
 				match x {
 					V3(x) => Ok(x),
-					V4(x) => x.try_into(),
+					V4(x) => x.try_into().map_err(|_| ()),
+					V5(x) => {
+						let v4: $v4 = x.try_into().map_err(|_| ())?;
+						v4.try_into().map_err(|_| ())
+					}
 				}
 			}
 		}
@@ -162,137 +177,21 @@ macro_rules! versioned_type {
 				match x {
 					V3(x) => x.try_into().map_err(|_| ()),
 					V4(x) => Ok(x),
+					V5(x) => x.try_into().map_err(|_| ()),
 				}
 			}
 		}
-		impl MaxEncodedLen for $n {
-			fn max_encoded_len() -> usize {
-				<$v3>::max_encoded_len()
-			}
-		}
-		impl IdentifyVersion for $n {
-			fn identify_version(&self) -> Version {
-				use $n::*;
-				match self {
-					V3(_) => v3::VERSION,
-					V4(_) => v4::VERSION,
-				}
-			}
-		}
-	};
-
-	($(#[$attr:meta])* pub enum $n:ident {
-		$(#[$index2:meta])+
-		V2($v2:ty),
-		$(#[$index3:meta])+
-		V3($v3:ty),
-		$(#[$index4:meta])+
-		V4($v4:ty),
-	}) => {
-		#[derive(Derivative, Encode, Decode, TypeInfo)]
-		#[derivative(
-			Clone(bound = ""),
-			Eq(bound = ""),
-			PartialEq(bound = ""),
-			Debug(bound = "")
-		)]
-		#[codec(encode_bound())]
-		#[codec(decode_bound())]
-		#[scale_info(replace_segment("staging_xcm", "xcm"))]
-		$(#[$attr])*
-		pub enum $n {
-			$(#[$index2])*
-			V2($v2),
-			$(#[$index3])*
-			V3($v3),
-			$(#[$index4])*
-			V4($v4),
-		}
-		impl $n {
-			pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
-				<Self as TryAs<T>>::try_as(&self)
-			}
-		}
-		impl TryAs<$v2> for $n {
-			fn try_as(&self) -> Result<&$v2, ()> {
-				match &self {
-					Self::V2(ref x) => Ok(x),
-					_ => Err(()),
-				}
-			}
-		}
-		impl TryAs<$v3> for $n {
-			fn try_as(&self) -> Result<&$v3, ()> {
-				match &self {
-					Self::V3(ref x) => Ok(x),
-					_ => Err(()),
-				}
-			}
-		}
-		impl TryAs<$v4> for $n {
-			fn try_as(&self) -> Result<&$v4, ()> {
-				match &self {
-					Self::V4(ref x) => Ok(x),
-					_ => Err(()),
-				}
-			}
-		}
-		impl IntoVersion for $n {
-			fn into_version(self, n: Version) -> Result<Self, ()> {
-				Ok(match n {
-					1 | 2 => Self::V2(self.try_into()?),
-					3 => Self::V3(self.try_into()?),
-					4 => Self::V4(self.try_into()?),
-					_ => return Err(()),
-				})
-			}
-		}
-		impl From<$v2> for $n {
-			fn from(x: $v2) -> Self {
-				$n::V2(x)
-			}
-		}
-		impl<T: Into<$v4>> From<T> for $n {
-			fn from(x: T) -> Self {
-				$n::V4(x.into())
-			}
-		}
-		impl TryFrom<$n> for $v2 {
+		impl TryFrom<$n> for $v5 {
 			type Error = ();
 			fn try_from(x: $n) -> Result<Self, ()> {
 				use $n::*;
 				match x {
-					V2(x) => Ok(x),
-					V3(x) => x.try_into(),
-					V4(x) => {
-						let v3: $v3 = x.try_into().map_err(|_| ())?;
-						v3.try_into()
+					V3(x) => {
+						let v4: $v4 = x.try_into().map_err(|_| ())?;
+						v4.try_into().map_err(|_| ())
 					},
-				}
-			}
-		}
-		impl TryFrom<$n> for $v3 {
-			type Error = ();
-			fn try_from(x: $n) -> Result<Self, ()> {
-				use $n::*;
-				match x {
-					V2(x) => x.try_into(),
-					V3(x) => Ok(x),
 					V4(x) => x.try_into().map_err(|_| ()),
-				}
-			}
-		}
-		impl TryFrom<$n> for $v4 {
-			type Error = ();
-			fn try_from(x: $n) -> Result<Self, ()> {
-				use $n::*;
-				match x {
-					V2(x) => {
-						let v3: $v3 = x.try_into().map_err(|_| ())?;
-						v3.try_into().map_err(|_| ())
-					},
-					V3(x) => x.try_into().map_err(|_| ()),
-					V4(x) => Ok(x),
+					V5(x) => Ok(x),
 				}
 			}
 		}
@@ -305,9 +204,9 @@ macro_rules! versioned_type {
 			fn identify_version(&self) -> Version {
 				use $n::*;
 				match self {
-					V2(_) => v2::VERSION,
 					V3(_) => v3::VERSION,
 					V4(_) => v4::VERSION,
+					V5(_) => v5::VERSION,
 				}
 			}
 		}
@@ -321,42 +220,44 @@ versioned_type! {
 		V3(v3::AssetId),
 		#[codec(index = 4)]
 		V4(v4::AssetId),
+		#[codec(index = 5)]
+		V5(v5::AssetId),
 	}
 }
 
 versioned_type! {
 	/// A single version's `Response` value, together with its version code.
 	pub enum VersionedResponse {
-		#[codec(index = 2)]
-		V2(v2::Response),
 		#[codec(index = 3)]
 		V3(v3::Response),
 		#[codec(index = 4)]
 		V4(v4::Response),
+		#[codec(index = 5)]
+		V5(v5::Response),
 	}
 }
 
 versioned_type! {
 	/// A single `NetworkId` value, together with its version code.
 	pub enum VersionedNetworkId {
-		#[codec(index = 2)]
-		V2(v2::NetworkId),
 		#[codec(index = 3)]
 		V3(v3::NetworkId),
 		#[codec(index = 4)]
 		V4(v4::NetworkId),
+		#[codec(index = 5)]
+		V5(v5::NetworkId),
 	}
 }
 
 versioned_type! {
 	/// A single `Junction` value, together with its version code.
 	pub enum VersionedJunction {
-		#[codec(index = 2)]
-		V2(v2::Junction),
 		#[codec(index = 3)]
 		V3(v3::Junction),
 		#[codec(index = 4)]
 		V4(v4::Junction),
+		#[codec(index = 5)]
+		V5(v5::Junction),
 	}
 }
 
@@ -364,63 +265,51 @@ versioned_type! {
 	/// A single `Location` value, together with its version code.
 	#[derive(Ord, PartialOrd)]
 	pub enum VersionedLocation {
-		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
-		V2(v2::MultiLocation),
 		#[codec(index = 3)]
 		V3(v3::MultiLocation),
 		#[codec(index = 4)]
 		V4(v4::Location),
+		#[codec(index = 5)]
+		V5(v5::Location),
 	}
 }
 
-#[deprecated(note = "Use `VersionedLocation` instead")]
-pub type VersionedMultiLocation = VersionedLocation;
-
 versioned_type! {
 	/// A single `InteriorLocation` value, together with its version code.
 	pub enum VersionedInteriorLocation {
-		#[codec(index = 2)] // while this is same as v1::Junctions, VersionedInteriorLocation is introduced in v3
-		V2(v2::InteriorMultiLocation),
 		#[codec(index = 3)]
 		V3(v3::InteriorMultiLocation),
 		#[codec(index = 4)]
 		V4(v4::InteriorLocation),
+		#[codec(index = 5)]
+		V5(v5::InteriorLocation),
 	}
 }
 
-#[deprecated(note = "Use `VersionedInteriorLocation` instead")]
-pub type VersionedInteriorMultiLocation = VersionedInteriorLocation;
-
 versioned_type! {
 	/// A single `Asset` value, together with its version code.
 	pub enum VersionedAsset {
-		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
-		V2(v2::MultiAsset),
 		#[codec(index = 3)]
 		V3(v3::MultiAsset),
 		#[codec(index = 4)]
 		V4(v4::Asset),
+		#[codec(index = 5)]
+		V5(v5::Asset),
 	}
 }
 
-#[deprecated(note = "Use `VersionedAsset` instead")]
-pub type VersionedMultiAsset = VersionedAsset;
-
 versioned_type! {
 	/// A single `MultiAssets` value, together with its version code.
 	pub enum VersionedAssets {
-		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
-		V2(v2::MultiAssets),
 		#[codec(index = 3)]
 		V3(v3::MultiAssets),
 		#[codec(index = 4)]
 		V4(v4::Assets),
+		#[codec(index = 5)]
+		V5(v5::Assets),
 	}
 }
 
-#[deprecated(note = "Use `VersionedAssets` instead")]
-pub type VersionedMultiAssets = VersionedAssets;
-
 /// A single XCM message, together with its version code.
 #[derive(Derivative, Encode, Decode, TypeInfo)]
 #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
@@ -429,21 +318,20 @@ pub type VersionedMultiAssets = VersionedAssets;
 #[scale_info(bounds(), skip_type_params(RuntimeCall))]
 #[scale_info(replace_segment("staging_xcm", "xcm"))]
 pub enum VersionedXcm<RuntimeCall> {
-	#[codec(index = 2)]
-	#[deprecated]
-	V2(v2::Xcm<RuntimeCall>),
 	#[codec(index = 3)]
 	V3(v3::Xcm<RuntimeCall>),
 	#[codec(index = 4)]
 	V4(v4::Xcm<RuntimeCall>),
+	#[codec(index = 5)]
+	V5(v5::Xcm<RuntimeCall>),
 }
 
-impl<C> IntoVersion for VersionedXcm<C> {
+impl<C: Decode + GetDispatchInfo> IntoVersion for VersionedXcm<C> {
 	fn into_version(self, n: Version) -> Result<Self, ()> {
 		Ok(match n {
-			2 => Self::V2(self.try_into()?),
 			3 => Self::V3(self.try_into()?),
 			4 => Self::V4(self.try_into()?),
+			5 => Self::V5(self.try_into()?),
 			_ => return Err(()),
 		})
 	}
@@ -452,9 +340,9 @@ impl<C> IntoVersion for VersionedXcm<C> {
 impl<C> IdentifyVersion for VersionedXcm<C> {
 	fn identify_version(&self) -> Version {
 		match self {
-			Self::V2(_) => v2::VERSION,
 			Self::V3(_) => v3::VERSION,
 			Self::V4(_) => v4::VERSION,
+			Self::V5(_) => v5::VERSION,
 		}
 	}
 }
@@ -476,12 +364,6 @@ impl<C> VersionedXcm<C> {
 	}
 }
 
-impl<RuntimeCall> From<v2::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
-	fn from(x: v2::Xcm<RuntimeCall>) -> Self {
-		VersionedXcm::V2(x)
-	}
-}
-
 impl<RuntimeCall> From<v3::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
 	fn from(x: v3::Xcm<RuntimeCall>) -> Self {
 		VersionedXcm::V3(x)
@@ -494,44 +376,50 @@ impl<RuntimeCall> From<v4::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
 	}
 }
 
-impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v2::Xcm<RuntimeCall> {
+impl<RuntimeCall> From<v5::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
+	fn from(x: v5::Xcm<RuntimeCall>) -> Self {
+		VersionedXcm::V5(x)
+	}
+}
+
+impl<Call: Decode + GetDispatchInfo> TryFrom<VersionedXcm<Call>> for v3::Xcm<Call> {
 	type Error = ();
-	fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
+	fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
 		use VersionedXcm::*;
 		match x {
-			V2(x) => Ok(x),
-			V3(x) => x.try_into(),
-			V4(x) => {
-				let v3: v3::Xcm<RuntimeCall> = x.try_into()?;
-				v3.try_into()
+			V3(x) => Ok(x),
+			V4(x) => x.try_into(),
+			V5(x) => {
+				let v4: v4::Xcm<Call> = x.try_into()?;
+				v4.try_into()
 			},
 		}
 	}
 }
 
-impl<Call> TryFrom<VersionedXcm<Call>> for v3::Xcm<Call> {
+impl<Call: Decode + GetDispatchInfo> TryFrom<VersionedXcm<Call>> for v4::Xcm<Call> {
 	type Error = ();
 	fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
 		use VersionedXcm::*;
 		match x {
-			V2(x) => x.try_into(),
-			V3(x) => Ok(x),
-			V4(x) => x.try_into(),
+			V3(x) => x.try_into(),
+			V4(x) => Ok(x),
+			V5(x) => x.try_into(),
 		}
 	}
 }
 
-impl<Call> TryFrom<VersionedXcm<Call>> for v4::Xcm<Call> {
+impl<Call: Decode + GetDispatchInfo> TryFrom<VersionedXcm<Call>> for v5::Xcm<Call> {
 	type Error = ();
 	fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
 		use VersionedXcm::*;
 		match x {
-			V2(x) => {
-				let v3: v3::Xcm<Call> = x.try_into()?;
-				v3.try_into()
+			V3(x) => {
+				let v4: v4::Xcm<Call> = x.try_into()?;
+				v4.try_into()
 			},
-			V3(x) => x.try_into(),
-			V4(x) => Ok(x),
+			V4(x) => x.try_into(),
+			V5(x) => Ok(x),
 		}
 	}
 }
@@ -539,7 +427,7 @@ impl<Call> TryFrom<VersionedXcm<Call>> for v4::Xcm<Call> {
 /// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `Location` which will
 /// interpret it.
 pub trait WrapVersion {
-	fn wrap_version<RuntimeCall>(
+	fn wrap_version<RuntimeCall: Decode + GetDispatchInfo>(
 		dest: &latest::Location,
 		xcm: impl Into<VersionedXcm<RuntimeCall>>,
 	) -> Result<VersionedXcm<RuntimeCall>, ()>;
@@ -568,28 +456,11 @@ impl WrapVersion for () {
 	}
 }
 
-/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before
-/// wrapping it.
-pub struct AlwaysV2;
-impl WrapVersion for AlwaysV2 {
-	fn wrap_version<RuntimeCall>(
-		_: &latest::Location,
-		xcm: impl Into<VersionedXcm<RuntimeCall>>,
-	) -> Result<VersionedXcm<RuntimeCall>, ()> {
-		Ok(VersionedXcm::<RuntimeCall>::V2(xcm.into().try_into()?))
-	}
-}
-impl GetVersion for AlwaysV2 {
-	fn get_version_for(_dest: &latest::Location) -> Option<Version> {
-		Some(v2::VERSION)
-	}
-}
-
 /// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before
 /// wrapping it.
 pub struct AlwaysV3;
 impl WrapVersion for AlwaysV3 {
-	fn wrap_version<Call>(
+	fn wrap_version<Call: Decode + GetDispatchInfo>(
 		_: &latest::Location,
 		xcm: impl Into<VersionedXcm<Call>>,
 	) -> Result<VersionedXcm<Call>, ()> {
@@ -606,7 +477,7 @@ impl GetVersion for AlwaysV3 {
 /// wrapping it.
 pub struct AlwaysV4;
 impl WrapVersion for AlwaysV4 {
-	fn wrap_version<Call>(
+	fn wrap_version<Call: Decode + GetDispatchInfo>(
 		_: &latest::Location,
 		xcm: impl Into<VersionedXcm<Call>>,
 	) -> Result<VersionedXcm<Call>, ()> {
@@ -619,9 +490,26 @@ impl GetVersion for AlwaysV4 {
 	}
 }
 
+/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before
+/// wrapping it.
+pub struct AlwaysV5;
+impl WrapVersion for AlwaysV5 {
+	fn wrap_version<Call: Decode + GetDispatchInfo>(
+		_: &latest::Location,
+		xcm: impl Into<VersionedXcm<Call>>,
+	) -> Result<VersionedXcm<Call>, ()> {
+		Ok(VersionedXcm::<Call>::V5(xcm.into().try_into()?))
+	}
+}
+impl GetVersion for AlwaysV5 {
+	fn get_version_for(_dest: &latest::Location) -> Option<Version> {
+		Some(v5::VERSION)
+	}
+}
+
 /// `WrapVersion` implementation which attempts to always convert the XCM to the latest version
 /// before wrapping it.
-pub type AlwaysLatest = AlwaysV4;
+pub type AlwaysLatest = AlwaysV5;
 
 /// `WrapVersion` implementation which attempts to always convert the XCM to the most recent Long-
 /// Term-Support version before wrapping it.
@@ -629,7 +517,7 @@ pub type AlwaysLts = AlwaysV4;
 
 pub mod prelude {
 	pub use super::{
-		latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, AlwaysV4, GetVersion,
+		latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV3, AlwaysV4, AlwaysV5, GetVersion,
 		IdentifyVersion, IntoVersion, Unsupported, Version as XcmVersion, VersionedAsset,
 		VersionedAssetId, VersionedAssets, VersionedInteriorLocation, VersionedLocation,
 		VersionedResponse, VersionedXcm, WrapVersion,
@@ -637,12 +525,6 @@ pub mod prelude {
 }
 
 pub mod opaque {
-	pub mod v2 {
-		// Everything from v2
-		pub use crate::v2::*;
-		// Then override with the opaque types in v2
-		pub use crate::v2::opaque::{Instruction, Xcm};
-	}
 	pub mod v3 {
 		// Everything from v3
 		pub use crate::v3::*;
@@ -655,9 +537,15 @@ pub mod opaque {
 		// Then override with the opaque types in v4
 		pub use crate::v4::opaque::{Instruction, Xcm};
 	}
+	pub mod v5 {
+		// Everything from v4
+		pub use crate::v5::*;
+		// Then override with the opaque types in v5
+		pub use crate::v5::opaque::{Instruction, Xcm};
+	}
 
 	pub mod latest {
-		pub use super::v4::*;
+		pub use super::v5::*;
 	}
 
 	pub mod lts {
@@ -709,7 +597,7 @@ fn size_limits() {
     }
 
 	check_sizes! {
-		(crate::latest::Instruction<()>, 112),
+		(crate::latest::Instruction<()>, 128),
 		(crate::latest::Asset, 80),
 		(crate::latest::Location, 24),
 		(crate::latest::AssetId, 40),
diff --git a/polkadot/xcm/src/tests.rs b/polkadot/xcm/src/tests.rs
index 4c666063f3f..5a267b3a904 100644
--- a/polkadot/xcm/src/tests.rs
+++ b/polkadot/xcm/src/tests.rs
@@ -34,43 +34,43 @@ fn encode_decode_versioned_asset_id_v3() {
 }
 
 #[test]
-fn encode_decode_versioned_response_v2() {
-	let response = VersionedResponse::V2(v2::Response::Null);
+fn encode_decode_versioned_response_v3() {
+	let response = VersionedResponse::V3(v3::Response::Null);
 	let encoded = response.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("0200"), "encode format changed");
-	assert_eq!(encoded[0], 2, "bad version number");
+	assert_eq!(encoded, hex_literal::hex!("0300"), "encode format changed");
+	assert_eq!(encoded[0], 3, "bad version number");
 
 	let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap();
 	assert_eq!(response, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_response_v3() {
-	let response = VersionedResponse::V3(v3::Response::Null);
+fn encode_decode_versioned_response_v4() {
+	let response = VersionedResponse::V4(v4::Response::Null);
 	let encoded = response.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("0300"), "encode format changed");
-	assert_eq!(encoded[0], 3, "bad version number");
+	assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
 
 	let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap();
 	assert_eq!(response, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_multi_location_v2() {
-	let location = VersionedLocation::V2(v2::MultiLocation::new(0, v2::Junctions::Here));
-	let encoded = location.encode();
+fn encode_decode_versioned_response_v5() {
+	let response = VersionedResponse::V5(v5::Response::Null);
+	let encoded = response.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("010000"), "encode format changed");
-	assert_eq!(encoded[0], 1, "bad version number"); // this is introduced in v1
+	assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
 
-	let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap();
-	assert_eq!(location, decoded);
+	let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(response, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_multi_location_v3() {
+fn encode_decode_versioned_location_v3() {
 	let location = VersionedLocation::V3(v3::MultiLocation::new(0, v3::Junctions::Here));
 	let encoded = location.encode();
 
@@ -82,19 +82,31 @@ fn encode_decode_versioned_multi_location_v3() {
 }
 
 #[test]
-fn encode_decode_versioned_interior_multi_location_v2() {
-	let location = VersionedInteriorLocation::V2(v2::InteriorMultiLocation::Here);
+fn encode_decode_versioned_location_v4() {
+	let location = VersionedLocation::V4(v4::Location::new(0, v4::Junctions::Here));
 	let encoded = location.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("0200"), "encode format changed");
-	assert_eq!(encoded[0], 2, "bad version number");
+	assert_eq!(encoded, hex_literal::hex!("040000"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
 
-	let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap();
+	let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap();
 	assert_eq!(location, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_interior_multi_location_v3() {
+fn encode_decode_versioned_location_v5() {
+	let location = VersionedLocation::V5(v5::Location::new(0, v5::Junctions::Here));
+	let encoded = location.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("050000"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
+
+	let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(location, decoded);
+}
+
+#[test]
+fn encode_decode_versioned_interior_location_v3() {
 	let location = VersionedInteriorLocation::V3(v3::InteriorMultiLocation::Here);
 	let encoded = location.encode();
 
@@ -106,19 +118,31 @@ fn encode_decode_versioned_interior_multi_location_v3() {
 }
 
 #[test]
-fn encode_decode_versioned_multi_asset_v2() {
-	let asset = VersionedAsset::V2(v2::MultiAsset::from(((0, v2::Junctions::Here), 1)));
-	let encoded = asset.encode();
+fn encode_decode_versioned_interior_location_v4() {
+	let location = VersionedInteriorLocation::V4(v4::InteriorLocation::Here);
+	let encoded = location.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("010000000004"), "encode format changed");
-	assert_eq!(encoded[0], 1, "bad version number");
+	assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
 
-	let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap();
-	assert_eq!(asset, decoded);
+	let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(location, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_multi_asset_v3() {
+fn encode_decode_versioned_interior_location_v5() {
+	let location = VersionedInteriorLocation::V5(v5::InteriorLocation::Here);
+	let encoded = location.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
+
+	let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(location, decoded);
+}
+
+#[test]
+fn encode_decode_versioned_asset_v3() {
 	let asset = VersionedAsset::V3(v3::MultiAsset::from((v3::MultiLocation::default(), 1)));
 	let encoded = asset.encode();
 
@@ -130,22 +154,31 @@ fn encode_decode_versioned_multi_asset_v3() {
 }
 
 #[test]
-fn encode_decode_versioned_multi_assets_v2() {
-	let assets = VersionedAssets::V2(v2::MultiAssets::from(vec![v2::MultiAsset::from((
-		(0, v2::Junctions::Here),
-		1,
-	))]));
-	let encoded = assets.encode();
+fn encode_decode_versioned_asset_v4() {
+	let asset = VersionedAsset::V4(v4::Asset::from((v4::Location::default(), 1)));
+	let encoded = asset.encode();
 
-	assert_eq!(encoded, hex_literal::hex!("01040000000004"), "encode format changed");
-	assert_eq!(encoded[0], 1, "bad version number");
+	assert_eq!(encoded, hex_literal::hex!("0400000004"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
 
-	let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap();
-	assert_eq!(assets, decoded);
+	let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(asset, decoded);
 }
 
 #[test]
-fn encode_decode_versioned_multi_assets_v3() {
+fn encode_decode_versioned_asset_v5() {
+	let asset = VersionedAsset::V5(v5::Asset::from((v5::Location::default(), 1)));
+	let encoded = asset.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("0500000004"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
+
+	let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(asset, decoded);
+}
+
+#[test]
+fn encode_decode_versioned_assets_v3() {
 	let assets = VersionedAssets::V3(v3::MultiAssets::from(vec![
 		(v3::MultiAsset::from((v3::MultiLocation::default(), 1))),
 	]));
@@ -158,6 +191,34 @@ fn encode_decode_versioned_multi_assets_v3() {
 	assert_eq!(assets, decoded);
 }
 
+#[test]
+fn encode_decode_versioned_assets_v4() {
+	let assets = VersionedAssets::V4(v4::Assets::from(vec![
+		(v4::Asset::from((v4::Location::default(), 1))),
+	]));
+	let encoded = assets.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("040400000004"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
+
+	let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(assets, decoded);
+}
+
+#[test]
+fn encode_decode_versioned_assets_v5() {
+	let assets = VersionedAssets::V5(v5::Assets::from(vec![
+		(v5::Asset::from((v5::Location::default(), 1))),
+	]));
+	let encoded = assets.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("050400000004"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
+
+	let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(assets, decoded);
+}
+
 #[test]
 fn encode_decode_versioned_xcm_v3() {
 	let xcm = VersionedXcm::V3(v3::Xcm::<()>::new());
@@ -170,6 +231,30 @@ fn encode_decode_versioned_xcm_v3() {
 	assert_eq!(xcm, decoded);
 }
 
+#[test]
+fn encode_decode_versioned_xcm_v4() {
+	let xcm = VersionedXcm::V4(v4::Xcm::<()>::new());
+	let encoded = xcm.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed");
+	assert_eq!(encoded[0], 4, "bad version number");
+
+	let decoded = VersionedXcm::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(xcm, decoded);
+}
+
+#[test]
+fn encode_decode_versioned_xcm_v5() {
+	let xcm = VersionedXcm::V5(v5::Xcm::<()>::new());
+	let encoded = xcm.encode();
+
+	assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed");
+	assert_eq!(encoded[0], 5, "bad version number");
+
+	let decoded = VersionedXcm::decode(&mut &encoded[..]).unwrap();
+	assert_eq!(xcm, decoded);
+}
+
 // With the renaming of the crate to `staging-xcm` the naming in the metadata changed as well and
 // this broke downstream users. This test ensures that the name in the metadata isn't changed.
 #[test]
diff --git a/polkadot/xcm/src/v2/junction.rs b/polkadot/xcm/src/v2/junction.rs
deleted file mode 100644
index 68a7886f303..00000000000
--- a/polkadot/xcm/src/v2/junction.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Support data structures for `MultiLocation`, primarily the `Junction` datatype.
-
-use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId};
-use crate::v3::Junction as NewJunction;
-use bounded_collections::{ConstU32, WeakBoundedVec};
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-/// A single item in a path to describe the relative location of a consensus system.
-///
-/// Each item assumes a pre-existing location as its context and is defined in terms of it.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Junction {
-	/// An indexed parachain belonging to and operated by the context.
-	///
-	/// Generally used when the context is a Polkadot Relay-chain.
-	Parachain(#[codec(compact)] u32),
-	/// A 32-byte identifier for an account of a specific network that is respected as a sovereign
-	/// endpoint within the context.
-	///
-	/// Generally used when the context is a Substrate-based chain.
-	AccountId32 { network: NetworkId, id: [u8; 32] },
-	/// An 8-byte index for an account of a specific network that is respected as a sovereign
-	/// endpoint within the context.
-	///
-	/// May be used when the context is a Frame-based chain and includes e.g. an indices pallet.
-	AccountIndex64 {
-		network: NetworkId,
-		#[codec(compact)]
-		index: u64,
-	},
-	/// A 20-byte identifier for an account of a specific network that is respected as a sovereign
-	/// endpoint within the context.
-	///
-	/// May be used when the context is an Ethereum or Bitcoin chain or smart-contract.
-	AccountKey20 { network: NetworkId, key: [u8; 20] },
-	/// An instanced, indexed pallet that forms a constituent part of the context.
-	///
-	/// Generally used when the context is a Frame-based chain.
-	PalletInstance(u8),
-	/// A non-descript index within the context location.
-	///
-	/// Usage will vary widely owing to its generality.
-	///
-	/// NOTE: Try to avoid using this and instead use a more specific item.
-	GeneralIndex(#[codec(compact)] u128),
-	/// A nondescript datum acting as a key within the context location.
-	///
-	/// Usage will vary widely owing to its generality.
-	///
-	/// NOTE: Try to avoid using this and instead use a more specific item.
-	GeneralKey(WeakBoundedVec<u8, ConstU32<32>>),
-	/// The unambiguous child.
-	///
-	/// Not currently used except as a fallback when deriving ancestry.
-	OnlyChild,
-	/// A pluralistic body existing within consensus.
-	///
-	/// Typical to be used to represent a governance origin of a chain, but could in principle be
-	/// used to represent things such as multisigs also.
-	Plurality { id: BodyId, part: BodyPart },
-}
-
-impl TryFrom<NewJunction> for Junction {
-	type Error = ();
-
-	fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
-		use NewJunction::*;
-		Ok(match value {
-			Parachain(id) => Self::Parachain(id),
-			AccountId32 { network, id } => Self::AccountId32 { network: network.try_into()?, id },
-			AccountIndex64 { network, index } =>
-				Self::AccountIndex64 { network: network.try_into()?, index },
-			AccountKey20 { network, key } =>
-				Self::AccountKey20 { network: network.try_into()?, key },
-			PalletInstance(index) => Self::PalletInstance(index),
-			GeneralIndex(id) => Self::GeneralIndex(id),
-			GeneralKey { length, data } => Self::GeneralKey(
-				data[0..data.len().min(length as usize)]
-					.to_vec()
-					.try_into()
-					.expect("key is bounded to 32 and so will never be out of bounds; qed"),
-			),
-			OnlyChild => Self::OnlyChild,
-			Plurality { id, part } => Self::Plurality { id: id.into(), part: part.into() },
-			_ => return Err(()),
-		})
-	}
-}
-
-impl Junction {
-	/// Convert `self` into a `MultiLocation` containing 0 parents.
-	///
-	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
-	pub const fn into(self) -> MultiLocation {
-		MultiLocation { parents: 0, interior: Junctions::X1(self) }
-	}
-
-	/// Convert `self` into a `MultiLocation` containing `n` parents.
-	///
-	/// Similar to `Self::into`, with the added ability to specify the number of parent junctions.
-	pub const fn into_exterior(self, n: u8) -> MultiLocation {
-		MultiLocation { parents: n, interior: Junctions::X1(self) }
-	}
-}
diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs
deleted file mode 100644
index e3358f08d41..00000000000
--- a/polkadot/xcm/src/v2/mod.rs
+++ /dev/null
@@ -1,1222 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! # XCM Version 2
-//!
-//! WARNING: DEPRECATED, please use version 3 or 4.
-//!
-//! Version 2 of the Cross-Consensus Message format data structures. The comprehensive list of
-//! changes can be found in
-//! [this PR description](https://github.com/paritytech/polkadot/pull/3629#issue-968428279).
-//!
-//! ## Changes to be aware of
-//! The biggest change here is the restructuring of XCM messages: instead of having `Order` and
-//! `Xcm` types, the `Xcm` type now simply wraps a `Vec` containing `Instruction`s. However, most
-//! changes should still be automatically convertible via the `try_from` and `from` conversion
-//! functions.
-//!
-//! ### Junction
-//! - No special attention necessary
-//!
-//! ### `MultiLocation`
-//! - No special attention necessary
-//!
-//! ### `MultiAsset`
-//! - No special attention necessary
-//!
-//! ### XCM and Order
-//! - `Xcm` and `Order` variants are now combined under a single `Instruction` enum.
-//! - `Order` is now obsolete and replaced entirely by `Instruction`.
-//! - `Xcm` is now a simple wrapper around a `Vec<Instruction>`.
-//! - During conversion from `Order` to `Instruction`, we do not handle `BuyExecution`s that have
-//!   nested XCMs, i.e. if the `instructions` field in the `BuyExecution` enum struct variant is not
-//!   empty, then the conversion will fail. To address this, rewrite the XCM using `Instruction`s in
-//!   chronological order.
-//! - During conversion from `Xcm` to `Instruction`, we do not handle `RelayedFrom` messages at all.
-//!
-//! ### XCM Pallet
-//! - The `Weigher` configuration item must have sensible weights defined for `BuyExecution` and
-//!   `DepositAsset` instructions. Failing that, dispatch calls to `teleport_assets` and
-//!   `reserve_transfer_assets` will fail with `UnweighableMessage`.
-
-use super::{
-	v3::{
-		BodyId as NewBodyId, BodyPart as NewBodyPart, Instruction as NewInstruction,
-		NetworkId as NewNetworkId, OriginKind as NewOriginKind, Response as NewResponse,
-		WeightLimit as NewWeightLimit, Xcm as NewXcm,
-	},
-	DoubleEncoded,
-};
-use alloc::{vec, vec::Vec};
-use bounded_collections::{ConstU32, WeakBoundedVec};
-use codec::{
-	self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
-	MaxEncodedLen,
-};
-use core::{fmt::Debug, result};
-use derivative::Derivative;
-use scale_info::TypeInfo;
-
-mod junction;
-mod multiasset;
-mod multilocation;
-mod traits;
-
-pub use junction::Junction;
-pub use multiasset::{
-	AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
-	WildFungibility, WildMultiAsset,
-};
-pub use multilocation::{
-	Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen,
-};
-pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendResult, SendXcm};
-
-/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
-#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
-pub enum OriginKind {
-	/// Origin should just be the native dispatch origin representation for the sender in the
-	/// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
-	/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
-	/// primary/native dispatch origin form.
-	Native,
-
-	/// Origin should just be the standard account-based origin with the sovereign account of
-	/// the sender. For Cumulus/Frame chains, this is the `Signed` origin.
-	SovereignAccount,
-
-	/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
-	/// This will not usually be an available option.
-	Superuser,
-
-	/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
-	/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
-	/// the `pallet_xcm::Origin::Xcm` type.
-	Xcm,
-}
-
-impl From<NewOriginKind> for OriginKind {
-	fn from(new: NewOriginKind) -> Self {
-		use NewOriginKind::*;
-		match new {
-			Native => Self::Native,
-			SovereignAccount => Self::SovereignAccount,
-			Superuser => Self::Superuser,
-			Xcm => Self::Xcm,
-		}
-	}
-}
-
-/// A global identifier of an account-bearing consensus system.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum NetworkId {
-	/// Unidentified/any.
-	Any,
-	/// Some named network.
-	Named(WeakBoundedVec<u8, ConstU32<32>>),
-	/// The Polkadot Relay chain
-	Polkadot,
-	/// Kusama.
-	Kusama,
-}
-
-impl TryFrom<Option<NewNetworkId>> for NetworkId {
-	type Error = ();
-	fn try_from(new: Option<NewNetworkId>) -> result::Result<NetworkId, ()> {
-		match new {
-			None => Ok(NetworkId::Any),
-			Some(id) => Self::try_from(id),
-		}
-	}
-}
-
-impl TryFrom<NewNetworkId> for NetworkId {
-	type Error = ();
-	fn try_from(new: NewNetworkId) -> result::Result<NetworkId, ()> {
-		use NewNetworkId::*;
-		match new {
-			Polkadot => Ok(NetworkId::Polkadot),
-			Kusama => Ok(NetworkId::Kusama),
-			_ => Err(()),
-		}
-	}
-}
-
-/// An identifier of a pluralistic body.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum BodyId {
-	/// The only body in its context.
-	Unit,
-	/// A named body.
-	Named(WeakBoundedVec<u8, ConstU32<32>>),
-	/// An indexed body.
-	Index(#[codec(compact)] u32),
-	/// The unambiguous executive body (for Polkadot, this would be the Polkadot council).
-	Executive,
-	/// The unambiguous technical body (for Polkadot, this would be the Technical Committee).
-	Technical,
-	/// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a
-	/// majority of lock-voters).
-	Legislative,
-	/// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a
-	/// "grand oracle", it may be considered as that).
-	Judicial,
-	/// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public
-	/// referendum on the `staking_admin` track).
-	Defense,
-	/// The unambiguous administration body (for Polkadot, an opinion on the topic given via a
-	/// public referendum on the `general_admin` track).
-	Administration,
-	/// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public
-	/// referendum on the `treasurer` track).
-	Treasury,
-}
-
-impl From<NewBodyId> for BodyId {
-	fn from(n: NewBodyId) -> Self {
-		use NewBodyId::*;
-		match n {
-			Unit => Self::Unit,
-			Moniker(n) => Self::Named(
-				n[..]
-					.to_vec()
-					.try_into()
-					.expect("array size is 4 and so will never be out of bounds; qed"),
-			),
-			Index(n) => Self::Index(n),
-			Executive => Self::Executive,
-			Technical => Self::Technical,
-			Legislative => Self::Legislative,
-			Judicial => Self::Judicial,
-			Defense => Self::Defense,
-			Administration => Self::Administration,
-			Treasury => Self::Treasury,
-		}
-	}
-}
-
-/// A part of a pluralistic body.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum BodyPart {
-	/// The body's declaration, under whatever means it decides.
-	Voice,
-	/// A given number of members of the body.
-	Members {
-		#[codec(compact)]
-		count: u32,
-	},
-	/// A given number of members of the body, out of some larger caucus.
-	Fraction {
-		#[codec(compact)]
-		nom: u32,
-		#[codec(compact)]
-		denom: u32,
-	},
-	/// No less than the given proportion of members of the body.
-	AtLeastProportion {
-		#[codec(compact)]
-		nom: u32,
-		#[codec(compact)]
-		denom: u32,
-	},
-	/// More than the given proportion of members of the body.
-	MoreThanProportion {
-		#[codec(compact)]
-		nom: u32,
-		#[codec(compact)]
-		denom: u32,
-	},
-}
-
-impl BodyPart {
-	/// Returns `true` if the part represents a strict majority (> 50%) of the body in question.
-	pub fn is_majority(&self) -> bool {
-		match self {
-			BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true,
-			BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true,
-			BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true,
-			_ => false,
-		}
-	}
-}
-
-impl From<NewBodyPart> for BodyPart {
-	fn from(n: NewBodyPart) -> Self {
-		use NewBodyPart::*;
-		match n {
-			Voice => Self::Voice,
-			Members { count } => Self::Members { count },
-			Fraction { nom, denom } => Self::Fraction { nom, denom },
-			AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
-			MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
-		}
-	}
-}
-
-/// This module's XCM version.
-pub const VERSION: super::Version = 2;
-
-/// An identifier for a query.
-pub type QueryId = u64;
-
-/// DEPRECATED. Please use XCMv3 or XCMv4 instead.
-#[derive(Derivative, Default, Encode, TypeInfo)]
-#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
-#[codec(encode_bound())]
-#[codec(decode_bound())]
-#[scale_info(bounds(), skip_type_params(RuntimeCall))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub struct Xcm<RuntimeCall>(pub Vec<Instruction<RuntimeCall>>);
-
-environmental::environmental!(instructions_count: u8);
-
-impl<Call> Decode for Xcm<Call> {
-	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
-		instructions_count::using_once(&mut 0, || {
-			let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
-			instructions_count::with(|count| {
-				*count = count.saturating_add(number_of_instructions as u8);
-				if *count > MAX_INSTRUCTIONS_TO_DECODE {
-					return Err(CodecError::from("Max instructions exceeded"))
-				}
-				Ok(())
-			})
-			.unwrap_or(Ok(()))?;
-			let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
-			Ok(Self(decoded_instructions))
-		})
-	}
-}
-
-/// The maximal number of instructions in an XCM before decoding fails.
-///
-/// This is a deliberate limit - not a technical one.
-pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
-
-impl<RuntimeCall> Xcm<RuntimeCall> {
-	/// Create an empty instance.
-	pub fn new() -> Self {
-		Self(vec![])
-	}
-
-	/// Return `true` if no instructions are held in `self`.
-	pub fn is_empty(&self) -> bool {
-		self.0.is_empty()
-	}
-
-	/// Return the number of instructions held in `self`.
-	pub fn len(&self) -> usize {
-		self.0.len()
-	}
-
-	/// Consume and either return `self` if it contains some instructions, or if it's empty, then
-	/// instead return the result of `f`.
-	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
-		if self.0.is_empty() {
-			f()
-		} else {
-			self
-		}
-	}
-
-	/// Return the first instruction, if any.
-	pub fn first(&self) -> Option<&Instruction<RuntimeCall>> {
-		self.0.first()
-	}
-
-	/// Return the last instruction, if any.
-	pub fn last(&self) -> Option<&Instruction<RuntimeCall>> {
-		self.0.last()
-	}
-
-	/// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise).
-	pub fn only(&self) -> Option<&Instruction<RuntimeCall>> {
-		if self.0.len() == 1 {
-			self.0.first()
-		} else {
-			None
-		}
-	}
-
-	/// Return the only instruction, contained in `Self`, iff only one exists (returns `self`
-	/// otherwise).
-	pub fn into_only(mut self) -> core::result::Result<Instruction<RuntimeCall>, Self> {
-		if self.0.len() == 1 {
-			self.0.pop().ok_or(self)
-		} else {
-			Err(self)
-		}
-	}
-}
-
-/// A prelude for importing all types typically used when interacting with XCM messages.
-pub mod prelude {
-	mod contents {
-		pub use super::super::{
-			Ancestor, AncestorThen,
-			AssetId::{self, *},
-			AssetInstance::{self, *},
-			BodyId, BodyPart, Error as XcmError, ExecuteXcm,
-			Fungibility::{self, *},
-			Instruction::*,
-			InteriorMultiLocation,
-			Junction::{self, *},
-			Junctions::{self, *},
-			MultiAsset,
-			MultiAssetFilter::{self, *},
-			MultiAssets, MultiLocation,
-			NetworkId::{self, *},
-			OriginKind, Outcome, Parent, ParentThen, QueryId, Response, Result as XcmResult,
-			SendError, SendResult, SendXcm,
-			WeightLimit::{self, *},
-			WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
-			WildMultiAsset::{self, *},
-			XcmWeightInfo, VERSION as XCM_VERSION,
-		};
-	}
-	pub use super::{Instruction, Xcm};
-	pub use contents::*;
-	pub mod opaque {
-		pub use super::{
-			super::opaque::{Instruction, Xcm},
-			contents::*,
-		};
-	}
-}
-
-/// Response data to a query.
-#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Response {
-	/// No response. Serves as a neutral default.
-	Null,
-	/// Some assets.
-	Assets(MultiAssets),
-	/// The outcome of an XCM instruction.
-	ExecutionResult(Option<(u32, Error)>),
-	/// An XCM version.
-	Version(super::Version),
-}
-
-impl Default for Response {
-	fn default() -> Self {
-		Self::Null
-	}
-}
-
-/// An optional weight limit.
-#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum WeightLimit {
-	/// No weight limit imposed.
-	Unlimited,
-	/// Weight limit imposed of the inner value.
-	Limited(#[codec(compact)] u64),
-}
-
-impl From<Option<u64>> for WeightLimit {
-	fn from(x: Option<u64>) -> Self {
-		match x {
-			Some(w) => WeightLimit::Limited(w),
-			None => WeightLimit::Unlimited,
-		}
-	}
-}
-
-impl From<WeightLimit> for Option<u64> {
-	fn from(x: WeightLimit) -> Self {
-		match x {
-			WeightLimit::Limited(w) => Some(w),
-			WeightLimit::Unlimited => None,
-		}
-	}
-}
-
-impl TryFrom<NewWeightLimit> for WeightLimit {
-	type Error = ();
-	fn try_from(x: NewWeightLimit) -> result::Result<Self, Self::Error> {
-		use NewWeightLimit::*;
-		match x {
-			Limited(w) => Ok(Self::Limited(w.ref_time())),
-			Unlimited => Ok(Self::Unlimited),
-		}
-	}
-}
-
-/// Local weight type; execution time in picoseconds.
-pub type Weight = u64;
-
-/// Cross-Consensus Message: A message from one consensus system to another.
-///
-/// Consensus systems that may send and receive messages include blockchains and smart contracts.
-///
-/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`.
-///
-/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the
-/// outer XCM format, known as `VersionedXcm`.
-#[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)]
-#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
-#[codec(encode_bound())]
-#[codec(decode_bound())]
-#[scale_info(bounds(), skip_type_params(RuntimeCall))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Instruction<RuntimeCall> {
-	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding
-	/// Register.
-	///
-	/// - `assets`: The asset(s) to be withdrawn into holding.
-	///
-	/// Kind: *Command*.
-	///
-	/// Errors:
-	WithdrawAsset(MultiAssets),
-
-	/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin`
-	/// system and equivalent derivatives should be placed into the Holding Register.
-	///
-	/// - `assets`: The asset(s) that are minted into holding.
-	///
-	/// Safety: `origin` must be trusted to have received and be storing `assets` such that they
-	/// may later be withdrawn should this system send a corresponding message.
-	///
-	/// Kind: *Trusted Indication*.
-	///
-	/// Errors:
-	ReserveAssetDeposited(MultiAssets),
-
-	/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should
-	/// be created and placed into the Holding Register.
-	///
-	/// - `assets`: The asset(s) that are minted into the Holding Register.
-	///
-	/// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets`
-	/// prior as a consequence of sending this message.
-	///
-	/// Kind: *Trusted Indication*.
-	///
-	/// Errors:
-	ReceiveTeleportedAsset(MultiAssets),
-
-	/// Respond with information that the local system is expecting.
-	///
-	/// - `query_id`: The identifier of the query that resulted in this message being sent.
-	/// - `response`: The message content.
-	/// - `max_weight`: The maximum weight that handling this response should take.
-	///
-	/// Safety: No concerns.
-	///
-	/// Kind: *Information*.
-	///
-	/// Errors:
-	QueryResponse {
-		#[codec(compact)]
-		query_id: QueryId,
-		response: Response,
-		#[codec(compact)]
-		max_weight: u64,
-	},
-
-	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
-	/// under the ownership of `beneficiary`.
-	///
-	/// - `assets`: The asset(s) to be withdrawn.
-	/// - `beneficiary`: The new owner for the assets.
-	///
-	/// Safety: No concerns.
-	///
-	/// Kind: *Command*.
-	///
-	/// Errors:
-	TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
-
-	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
-	/// under the ownership of `dest` within this consensus system (i.e. its sovereign account).
-	///
-	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given
-	/// `xcm`.
-	///
-	/// - `assets`: The asset(s) to be withdrawn.
-	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
-	///   beneficiary for the assets and the notification target for the reserve asset deposit
-	///   message.
-	/// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which
-	///   is sent onwards to `dest`.
-	///
-	/// Safety: No concerns.
-	///
-	/// Kind: *Command*.
-	///
-	/// Errors:
-	TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
-
-	/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed
-	/// by the kind of origin `origin_type`.
-	///
-	/// - `origin_type`: The means of expressing the message origin as a dispatch origin.
-	/// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight
-	///   and will be used in the weight determination arithmetic.
-	/// - `call`: The encoded transaction to be applied.
-	///
-	/// Safety: No concerns.
-	///
-	/// Kind: *Command*.
-	///
-	/// Errors:
-	Transact {
-		origin_type: OriginKind,
-		#[codec(compact)]
-		require_weight_at_most: u64,
-		call: DoubleEncoded<RuntimeCall>,
-	},
-
-	/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by
-	/// the relay-chain to a para.
-	///
-	/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel
-	///   opening.
-	/// - `max_message_size`: The maximum size of a message proposed by the sender.
-	/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
-	///
-	/// Safety: The message should originate directly from the relay-chain.
-	///
-	/// Kind: *System Notification*
-	HrmpNewChannelOpenRequest {
-		#[codec(compact)]
-		sender: u32,
-		#[codec(compact)]
-		max_message_size: u32,
-		#[codec(compact)]
-		max_capacity: u32,
-	},
-
-	/// A message to notify about that a previously sent open channel request has been accepted by
-	/// the recipient. That means that the channel will be opened during the next relay-chain
-	/// session change. This message is meant to be sent by the relay-chain to a para.
-	///
-	/// Safety: The message should originate directly from the relay-chain.
-	///
-	/// Kind: *System Notification*
-	///
-	/// Errors:
-	HrmpChannelAccepted {
-		// NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp
-		// items; and b) because the field's meaning is not obvious/mentioned from the item name.
-		#[codec(compact)]
-		recipient: u32,
-	},
-
-	/// A message to notify that the other party in an open channel decided to close it. In
-	/// particular, `initiator` is going to close the channel opened from `sender` to the
-	/// `recipient`. The close will be enacted at the next relay-chain session change. This message
-	/// is meant to be sent by the relay-chain to a para.
-	///
-	/// Safety: The message should originate directly from the relay-chain.
-	///
-	/// Kind: *System Notification*
-	///
-	/// Errors:
-	HrmpChannelClosing {
-		#[codec(compact)]
-		initiator: u32,
-		#[codec(compact)]
-		sender: u32,
-		#[codec(compact)]
-		recipient: u32,
-	},
-
-	/// Clear the origin.
-	///
-	/// This may be used by the XCM author to ensure that later instructions cannot command the
-	/// authority of the origin (e.g. if they are being relayed from an untrusted source, as often
-	/// the case with `ReserveAssetDeposited`).
-	///
-	/// Safety: No concerns.
-	///
-	/// Kind: *Command*.
-	///
-	/// Errors:
-	ClearOrigin,
-
-	/// Mutate the origin to some interior location.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	DescendOrigin(InteriorMultiLocation),
-
-	/// Immediately report the contents of the Error Register to the given destination via XCM.
-	///
-	/// A `QueryResponse` message of type `ExecutionOutcome` is sent to `dest` with the given
-	/// `query_id` and the outcome of the XCM.
-	///
-	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
-	/// - `dest`: A valid destination for the returned XCM message.
-	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
-	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
-	///   response may not execute at all.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	ReportError {
-		#[codec(compact)]
-		query_id: QueryId,
-		dest: MultiLocation,
-		#[codec(compact)]
-		max_response_weight: u64,
-	},
-
-	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
-	/// the ownership of `beneficiary` within this consensus system.
-	///
-	/// - `assets`: The asset(s) to remove from holding.
-	/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding.
-	///   Only the first `max_assets` assets/instances of those matched by `assets` will be
-	///   removed, prioritized under standard asset ordering. Any others will remain in holding.
-	/// - `beneficiary`: The new owner for the assets.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	DepositAsset {
-		assets: MultiAssetFilter,
-		#[codec(compact)]
-		max_assets: u32,
-		beneficiary: MultiLocation,
-	},
-
-	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
-	/// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign
-	/// account).
-	///
-	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
-	///
-	/// - `assets`: The asset(s) to remove from holding.
-	/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding.
-	///   Only the first `max_assets` assets/instances of those matched by `assets` will be
-	///   removed, prioritized under standard asset ordering. Any others will remain in holding.
-	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
-	///   beneficiary for the assets and the notification target for the reserve asset deposit
-	///   message.
-	/// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is
-	///   sent onwards to `dest`.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	DepositReserveAsset {
-		assets: MultiAssetFilter,
-		#[codec(compact)]
-		max_assets: u32,
-		dest: MultiLocation,
-		xcm: Xcm<()>,
-	},
-
-	/// Remove the asset(s) (`give`) from the Holding Register and replace them with alternative
-	/// assets.
-	///
-	/// The minimum amount of assets to be received into the Holding Register for the order not to
-	/// fail may be stated.
-	///
-	/// - `give`: The asset(s) to remove from holding.
-	/// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets },
-
-	/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a
-	/// reserve location.
-	///
-	/// - `assets`: The asset(s) to remove from holding.
-	/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The
-	///   sovereign account of this consensus system *on the reserve location* will have
-	///   appropriate assets withdrawn and `effects` will be executed on them. There will typically
-	///   be only one valid location on any given asset/chain combination.
-	/// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve
-	///   location*.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
-
-	/// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message
-	/// to a `dest` location.
-	///
-	/// - `assets`: The asset(s) to remove from holding.
-	/// - `dest`: A valid location that respects teleports coming from this location.
-	/// - `xcm`: The instructions to execute on the assets once arrived *on the destination
-	///   location*.
-	///
-	/// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for
-	/// all `assets`. If it does not, then the assets may be lost.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
-
-	/// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a
-	/// portion thereof.
-	///
-	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
-	/// - `dest`: A valid destination for the returned XCM message. This may be limited to the
-	///   current origin.
-	/// - `assets`: A filter for the assets that should be reported back. The assets reported back
-	///   will be, asset-wise, *the lesser of this value and the holding register*. No wildcards
-	///   will be used when reporting assets back.
-	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
-	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
-	///   response may not execute at all.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	QueryHolding {
-		#[codec(compact)]
-		query_id: QueryId,
-		dest: MultiLocation,
-		assets: MultiAssetFilter,
-		#[codec(compact)]
-		max_response_weight: u64,
-	},
-
-	/// Pay for the execution of some XCM `xcm` and `orders` with up to `weight`
-	/// picoseconds of execution time, paying for this with up to `fees` from the Holding Register.
-	///
-	/// - `fees`: The asset(s) to remove from the Holding Register to pay for fees.
-	/// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the
-	///   expected maximum weight of the total XCM to be executed for the
-	///   `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
-
-	/// Refund any surplus weight previously bought with `BuyExecution`.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: None.
-	RefundSurplus,
-
-	/// Set the Error Handler Register. This is code that should be called in the case of an error
-	/// happening.
-	///
-	/// An error occurring within execution of this code will _NOT_ result in the error register
-	/// being set, nor will an error handler be called due to it. The error handler and appendix
-	/// may each still be set.
-	///
-	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
-	/// weight however includes only the difference between the previous handler and the new
-	/// handler, which can reasonably be negative, which would result in a surplus.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: None.
-	SetErrorHandler(Xcm<RuntimeCall>),
-
-	/// Set the Appendix Register. This is code that should be called after code execution
-	/// (including the error handler if any) is finished. This will be called regardless of whether
-	/// an error occurred.
-	///
-	/// Any error occurring due to execution of this code will result in the error register being
-	/// set, and the error handler (if set) firing.
-	///
-	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
-	/// weight however includes only the difference between the previous appendix and the new
-	/// appendix, which can reasonably be negative, which would result in a surplus.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: None.
-	SetAppendix(Xcm<RuntimeCall>),
-
-	/// Clear the Error Register.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: None.
-	ClearError,
-
-	/// Create some assets which are being held on behalf of the origin.
-	///
-	/// - `assets`: The assets which are to be claimed. This must match exactly with the assets
-	///   claimable by the origin of the ticket.
-	/// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the
-	///   asset.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
-
-	/// Always throws an error of type `Trap`.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors:
-	/// - `Trap`: All circumstances, whose inner value is the same as this item's inner value.
-	Trap(#[codec(compact)] u64),
-
-	/// Ask the destination system to respond with the most recent version of XCM that they
-	/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
-	/// responses when they happen.
-	///
-	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
-	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
-	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
-	///   response may not execute at all.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: *Fallible*
-	SubscribeVersion {
-		#[codec(compact)]
-		query_id: QueryId,
-		#[codec(compact)]
-		max_response_weight: u64,
-	},
-
-	/// Cancel the effect of a previous `SubscribeVersion` instruction.
-	///
-	/// Kind: *Command*
-	///
-	/// Errors: *Fallible*
-	UnsubscribeVersion,
-}
-
-impl<RuntimeCall> Xcm<RuntimeCall> {
-	pub fn into<C>(self) -> Xcm<C> {
-		Xcm::from(self)
-	}
-	pub fn from<C>(xcm: Xcm<C>) -> Self {
-		Self(xcm.0.into_iter().map(Instruction::<RuntimeCall>::from).collect())
-	}
-}
-
-impl<RuntimeCall> Instruction<RuntimeCall> {
-	pub fn into<C>(self) -> Instruction<C> {
-		Instruction::from(self)
-	}
-	pub fn from<C>(xcm: Instruction<C>) -> Self {
-		use Instruction::*;
-		match xcm {
-			WithdrawAsset(assets) => WithdrawAsset(assets),
-			ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
-			ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
-			QueryResponse { query_id, response, max_weight } =>
-				QueryResponse { query_id, response, max_weight },
-			TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
-			TransferReserveAsset { assets, dest, xcm } =>
-				TransferReserveAsset { assets, dest, xcm },
-			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
-				HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
-			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
-			HrmpChannelClosing { initiator, sender, recipient } =>
-				HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_type, require_weight_at_most, call } =>
-				Transact { origin_type, require_weight_at_most, call: call.into() },
-			ReportError { query_id, dest, max_response_weight } =>
-				ReportError { query_id, dest, max_response_weight },
-			DepositAsset { assets, max_assets, beneficiary } =>
-				DepositAsset { assets, max_assets, beneficiary },
-			DepositReserveAsset { assets, max_assets, dest, xcm } =>
-				DepositReserveAsset { assets, max_assets, dest, xcm },
-			ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
-			InitiateReserveWithdraw { assets, reserve, xcm } =>
-				InitiateReserveWithdraw { assets, reserve, xcm },
-			InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
-			QueryHolding { query_id, dest, assets, max_response_weight } =>
-				QueryHolding { query_id, dest, assets, max_response_weight },
-			BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
-			ClearOrigin => ClearOrigin,
-			DescendOrigin(who) => DescendOrigin(who),
-			RefundSurplus => RefundSurplus,
-			SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
-			SetAppendix(xcm) => SetAppendix(xcm.into()),
-			ClearError => ClearError,
-			ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
-			Trap(code) => Trap(code),
-			SubscribeVersion { query_id, max_response_weight } =>
-				SubscribeVersion { query_id, max_response_weight },
-			UnsubscribeVersion => UnsubscribeVersion,
-		}
-	}
-}
-
-// TODO: Automate Generation
-impl<RuntimeCall, W: XcmWeightInfo<RuntimeCall>> GetWeight<W> for Instruction<RuntimeCall> {
-	fn weight(&self) -> sp_weights::Weight {
-		use Instruction::*;
-		match self {
-			WithdrawAsset(assets) => sp_weights::Weight::from_parts(W::withdraw_asset(assets), 0),
-			ReserveAssetDeposited(assets) =>
-				sp_weights::Weight::from_parts(W::reserve_asset_deposited(assets), 0),
-			ReceiveTeleportedAsset(assets) =>
-				sp_weights::Weight::from_parts(W::receive_teleported_asset(assets), 0),
-			QueryResponse { query_id, response, max_weight } =>
-				sp_weights::Weight::from_parts(W::query_response(query_id, response, max_weight), 0),
-			TransferAsset { assets, beneficiary } =>
-				sp_weights::Weight::from_parts(W::transfer_asset(assets, beneficiary), 0),
-			TransferReserveAsset { assets, dest, xcm } =>
-				sp_weights::Weight::from_parts(W::transfer_reserve_asset(&assets, dest, xcm), 0),
-			Transact { origin_type, require_weight_at_most, call } =>
-				sp_weights::Weight::from_parts(
-					W::transact(origin_type, require_weight_at_most, call),
-					0,
-				),
-			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
-				sp_weights::Weight::from_parts(
-					W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
-					0,
-				),
-			HrmpChannelAccepted { recipient } =>
-				sp_weights::Weight::from_parts(W::hrmp_channel_accepted(recipient), 0),
-			HrmpChannelClosing { initiator, sender, recipient } => sp_weights::Weight::from_parts(
-				W::hrmp_channel_closing(initiator, sender, recipient),
-				0,
-			),
-			ClearOrigin => sp_weights::Weight::from_parts(W::clear_origin(), 0),
-			DescendOrigin(who) => sp_weights::Weight::from_parts(W::descend_origin(who), 0),
-			ReportError { query_id, dest, max_response_weight } => sp_weights::Weight::from_parts(
-				W::report_error(query_id, dest, max_response_weight),
-				0,
-			),
-			DepositAsset { assets, max_assets, beneficiary } =>
-				sp_weights::Weight::from_parts(W::deposit_asset(assets, max_assets, beneficiary), 0),
-			DepositReserveAsset { assets, max_assets, dest, xcm } =>
-				sp_weights::Weight::from_parts(
-					W::deposit_reserve_asset(assets, max_assets, dest, xcm),
-					0,
-				),
-			ExchangeAsset { give, receive } =>
-				sp_weights::Weight::from_parts(W::exchange_asset(give, receive), 0),
-			InitiateReserveWithdraw { assets, reserve, xcm } => sp_weights::Weight::from_parts(
-				W::initiate_reserve_withdraw(assets, reserve, xcm),
-				0,
-			),
-			InitiateTeleport { assets, dest, xcm } =>
-				sp_weights::Weight::from_parts(W::initiate_teleport(assets, dest, xcm), 0),
-			QueryHolding { query_id, dest, assets, max_response_weight } =>
-				sp_weights::Weight::from_parts(
-					W::query_holding(query_id, dest, assets, max_response_weight),
-					0,
-				),
-			BuyExecution { fees, weight_limit } =>
-				sp_weights::Weight::from_parts(W::buy_execution(fees, weight_limit), 0),
-			RefundSurplus => sp_weights::Weight::from_parts(W::refund_surplus(), 0),
-			SetErrorHandler(xcm) => sp_weights::Weight::from_parts(W::set_error_handler(xcm), 0),
-			SetAppendix(xcm) => sp_weights::Weight::from_parts(W::set_appendix(xcm), 0),
-			ClearError => sp_weights::Weight::from_parts(W::clear_error(), 0),
-			ClaimAsset { assets, ticket } =>
-				sp_weights::Weight::from_parts(W::claim_asset(assets, ticket), 0),
-			Trap(code) => sp_weights::Weight::from_parts(W::trap(code), 0),
-			SubscribeVersion { query_id, max_response_weight } => sp_weights::Weight::from_parts(
-				W::subscribe_version(query_id, max_response_weight),
-				0,
-			),
-			UnsubscribeVersion => sp_weights::Weight::from_parts(W::unsubscribe_version(), 0),
-		}
-	}
-}
-
-pub mod opaque {
-	/// The basic concrete type of `Xcm`, which doesn't make any assumptions about the
-	/// format of a call other than it is pre-encoded.
-	pub type Xcm = super::Xcm<()>;
-
-	/// The basic concrete type of `Instruction`, which doesn't make any assumptions about the
-	/// format of a call other than it is pre-encoded.
-	pub type Instruction = super::Instruction<()>;
-}
-
-// Convert from a v3 response to a v2 response
-impl TryFrom<NewResponse> for Response {
-	type Error = ();
-	fn try_from(response: NewResponse) -> result::Result<Self, ()> {
-		Ok(match response {
-			NewResponse::Assets(assets) => Self::Assets(assets.try_into()?),
-			NewResponse::Version(version) => Self::Version(version),
-			NewResponse::ExecutionResult(error) => Self::ExecutionResult(match error {
-				Some((i, e)) => Some((i, e.try_into()?)),
-				None => None,
-			}),
-			NewResponse::Null => Self::Null,
-			_ => return Err(()),
-		})
-	}
-}
-
-// Convert from a v3 XCM to a v2 XCM.
-impl<RuntimeCall> TryFrom<NewXcm<RuntimeCall>> for Xcm<RuntimeCall> {
-	type Error = ();
-	fn try_from(new_xcm: NewXcm<RuntimeCall>) -> result::Result<Self, ()> {
-		Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
-	}
-}
-
-// Convert from a v3 instruction to a v2 instruction
-impl<RuntimeCall> TryFrom<NewInstruction<RuntimeCall>> for Instruction<RuntimeCall> {
-	type Error = ();
-	fn try_from(instruction: NewInstruction<RuntimeCall>) -> result::Result<Self, ()> {
-		use NewInstruction::*;
-		Ok(match instruction {
-			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
-			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
-			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
-			QueryResponse { query_id, response, max_weight, .. } => Self::QueryResponse {
-				query_id,
-				response: response.try_into()?,
-				max_weight: max_weight.ref_time(),
-			},
-			TransferAsset { assets, beneficiary } => Self::TransferAsset {
-				assets: assets.try_into()?,
-				beneficiary: beneficiary.try_into()?,
-			},
-			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
-				assets: assets.try_into()?,
-				dest: dest.try_into()?,
-				xcm: xcm.try_into()?,
-			},
-			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
-				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
-			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
-			HrmpChannelClosing { initiator, sender, recipient } =>
-				Self::HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
-				origin_type: origin_kind.into(),
-				require_weight_at_most: require_weight_at_most.ref_time(),
-				call: call.into(),
-			},
-			ReportError(response_info) => Self::ReportError {
-				query_id: response_info.query_id,
-				dest: response_info.destination.try_into()?,
-				max_response_weight: response_info.max_weight.ref_time(),
-			},
-			DepositAsset { assets, beneficiary } => {
-				let max_assets = assets.count().ok_or(())?;
-				let beneficiary = beneficiary.try_into()?;
-				let assets = assets.try_into()?;
-				Self::DepositAsset { assets, max_assets, beneficiary }
-			},
-			DepositReserveAsset { assets, dest, xcm } => {
-				let max_assets = assets.count().ok_or(())?;
-				let dest = dest.try_into()?;
-				let xcm = xcm.try_into()?;
-				let assets = assets.try_into()?;
-				Self::DepositReserveAsset { assets, max_assets, dest, xcm }
-			},
-			ExchangeAsset { give, want, .. } => {
-				let give = give.try_into()?;
-				let receive = want.try_into()?;
-				Self::ExchangeAsset { give, receive }
-			},
-			InitiateReserveWithdraw { assets, reserve, xcm } => {
-				// No `max_assets` here, so if there's a connt, then we cannot translate.
-				let assets = assets.try_into()?;
-				let reserve = reserve.try_into()?;
-				let xcm = xcm.try_into()?;
-				Self::InitiateReserveWithdraw { assets, reserve, xcm }
-			},
-			InitiateTeleport { assets, dest, xcm } => {
-				// No `max_assets` here, so if there's a connt, then we cannot translate.
-				let assets = assets.try_into()?;
-				let dest = dest.try_into()?;
-				let xcm = xcm.try_into()?;
-				Self::InitiateTeleport { assets, dest, xcm }
-			},
-			ReportHolding { response_info, assets } => Self::QueryHolding {
-				query_id: response_info.query_id,
-				dest: response_info.destination.try_into()?,
-				assets: assets.try_into()?,
-				max_response_weight: response_info.max_weight.ref_time(),
-			},
-			BuyExecution { fees, weight_limit } => {
-				let fees = fees.try_into()?;
-				let weight_limit = weight_limit.try_into()?;
-				Self::BuyExecution { fees, weight_limit }
-			},
-			ClearOrigin => Self::ClearOrigin,
-			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
-			RefundSurplus => Self::RefundSurplus,
-			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
-			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
-			ClearError => Self::ClearError,
-			ClaimAsset { assets, ticket } => {
-				let assets = assets.try_into()?;
-				let ticket = ticket.try_into()?;
-				Self::ClaimAsset { assets, ticket }
-			},
-			Trap(code) => Self::Trap(code),
-			SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
-				query_id,
-				max_response_weight: max_response_weight.ref_time(),
-			},
-			UnsubscribeVersion => Self::UnsubscribeVersion,
-			i => {
-				log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2");
-				return Err(());
-			},
-		})
-	}
-}
-
-#[cfg(test)]
-mod tests {
-	use super::{prelude::*, *};
-
-	#[test]
-	fn decoding_respects_limit() {
-		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
-		let encoded = max_xcm.encode();
-		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
-
-		let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
-		let encoded = big_xcm.encode();
-		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
-
-		let nested_xcm = Xcm::<()>(vec![
-			DepositReserveAsset {
-				assets: All.into(),
-				dest: Here.into(),
-				xcm: max_xcm,
-				max_assets: 1,
-			};
-			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
-		]);
-		let encoded = nested_xcm.encode();
-		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
-
-		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
-		let encoded = even_more_nested_xcm.encode();
-		assert_eq!(encoded.len(), 345730);
-		// This should not decode since the limit is 100
-		assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
-		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
-	}
-}
diff --git a/polkadot/xcm/src/v2/multiasset.rs b/polkadot/xcm/src/v2/multiasset.rs
deleted file mode 100644
index 218f21b63b0..00000000000
--- a/polkadot/xcm/src/v2/multiasset.rs
+++ /dev/null
@@ -1,626 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Cross-Consensus Message format asset data structures.
-//!
-//! This encompasses four types for representing assets:
-//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some
-//!   amount of a fungible.
-//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with
-//!   fungibles first.
-//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific
-//!   kind.
-//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently
-//!   filtering an XCM holding account.
-
-use super::MultiLocation;
-use crate::v3::{
-	AssetId as NewAssetId, AssetInstance as NewAssetInstance, Fungibility as NewFungibility,
-	MultiAsset as NewMultiAsset, MultiAssetFilter as NewMultiAssetFilter,
-	MultiAssets as NewMultiAssets, WildFungibility as NewWildFungibility,
-	WildMultiAsset as NewWildMultiAsset,
-};
-use alloc::{vec, vec::Vec};
-use codec::{self as codec, Decode, Encode};
-use core::cmp::Ordering;
-use scale_info::TypeInfo;
-
-/// A general identifier for an instance of a non-fungible asset class.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum AssetInstance {
-	/// Undefined - used if the non-fungible asset class has only one instance.
-	Undefined,
-
-	/// A compact index. Technically this could be greater than `u128`, but this implementation
-	/// supports only values up to `2**128 - 1`.
-	Index(#[codec(compact)] u128),
-
-	/// A 4-byte fixed-length datum.
-	Array4([u8; 4]),
-
-	/// An 8-byte fixed-length datum.
-	Array8([u8; 8]),
-
-	/// A 16-byte fixed-length datum.
-	Array16([u8; 16]),
-
-	/// A 32-byte fixed-length datum.
-	Array32([u8; 32]),
-
-	/// An arbitrary piece of data. Use only when necessary.
-	Blob(Vec<u8>),
-}
-
-impl From<()> for AssetInstance {
-	fn from(_: ()) -> Self {
-		Self::Undefined
-	}
-}
-
-impl From<[u8; 4]> for AssetInstance {
-	fn from(x: [u8; 4]) -> Self {
-		Self::Array4(x)
-	}
-}
-
-impl From<[u8; 8]> for AssetInstance {
-	fn from(x: [u8; 8]) -> Self {
-		Self::Array8(x)
-	}
-}
-
-impl From<[u8; 16]> for AssetInstance {
-	fn from(x: [u8; 16]) -> Self {
-		Self::Array16(x)
-	}
-}
-
-impl From<[u8; 32]> for AssetInstance {
-	fn from(x: [u8; 32]) -> Self {
-		Self::Array32(x)
-	}
-}
-
-impl From<Vec<u8>> for AssetInstance {
-	fn from(x: Vec<u8>) -> Self {
-		Self::Blob(x)
-	}
-}
-
-impl TryFrom<NewAssetInstance> for AssetInstance {
-	type Error = ();
-	fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
-		use NewAssetInstance::*;
-		Ok(match value {
-			Undefined => Self::Undefined,
-			Index(n) => Self::Index(n),
-			Array4(n) => Self::Array4(n),
-			Array8(n) => Self::Array8(n),
-			Array16(n) => Self::Array16(n),
-			Array32(n) => Self::Array32(n),
-		})
-	}
-}
-
-/// Classification of an asset being concrete or abstract.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum AssetId {
-	Concrete(MultiLocation),
-	Abstract(Vec<u8>),
-}
-
-impl<T: Into<MultiLocation>> From<T> for AssetId {
-	fn from(x: T) -> Self {
-		Self::Concrete(x.into())
-	}
-}
-
-impl From<Vec<u8>> for AssetId {
-	fn from(x: Vec<u8>) -> Self {
-		Self::Abstract(x)
-	}
-}
-
-impl TryFrom<NewAssetId> for AssetId {
-	type Error = ();
-	fn try_from(old: NewAssetId) -> Result<Self, ()> {
-		use NewAssetId::*;
-		Ok(match old {
-			Concrete(l) => Self::Concrete(l.try_into()?),
-			Abstract(v) => {
-				let zeroes = v.iter().rev().position(|n| *n != 0).unwrap_or(v.len());
-				Self::Abstract(v[0..(32 - zeroes)].to_vec())
-			},
-		})
-	}
-}
-
-impl AssetId {
-	/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
-	pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
-		if let AssetId::Concrete(ref mut l) = self {
-			l.prepend_with(prepend.clone()).map_err(|_| ())?;
-		}
-		Ok(())
-	}
-
-	/// Mutate the asset to represent the same value from the perspective of a new `target`
-	/// location. The local chain's location is provided in `ancestry`.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		if let AssetId::Concrete(ref mut l) = self {
-			l.reanchor(target, ancestry)?;
-		}
-		Ok(())
-	}
-
-	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
-	/// `MultiAsset` value.
-	pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
-		MultiAsset { fun, id: self }
-	}
-
-	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
-	/// `WildMultiAsset` wildcard (`AllOf`) value.
-	pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset {
-		WildMultiAsset::AllOf { fun, id: self }
-	}
-}
-
-/// Classification of whether an asset is fungible or not, along with a mandatory amount or
-/// instance.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Fungibility {
-	Fungible(#[codec(compact)] u128),
-	NonFungible(AssetInstance),
-}
-
-impl Fungibility {
-	pub fn is_kind(&self, w: WildFungibility) -> bool {
-		use Fungibility::*;
-		use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
-		matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
-	}
-}
-
-impl From<u128> for Fungibility {
-	fn from(amount: u128) -> Fungibility {
-		debug_assert_ne!(amount, 0);
-		Fungibility::Fungible(amount)
-	}
-}
-
-impl<T: Into<AssetInstance>> From<T> for Fungibility {
-	fn from(instance: T) -> Fungibility {
-		Fungibility::NonFungible(instance.into())
-	}
-}
-
-impl TryFrom<NewFungibility> for Fungibility {
-	type Error = ();
-	fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
-		use NewFungibility::*;
-		Ok(match value {
-			Fungible(n) => Self::Fungible(n),
-			NonFungible(i) => Self::NonFungible(i.try_into()?),
-		})
-	}
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub struct MultiAsset {
-	pub id: AssetId,
-	pub fun: Fungibility,
-}
-
-impl PartialOrd for MultiAsset {
-	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-		Some(self.cmp(other))
-	}
-}
-
-impl Ord for MultiAsset {
-	fn cmp(&self, other: &Self) -> Ordering {
-		match (&self.fun, &other.fun) {
-			(Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
-			(Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
-			_ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
-		}
-	}
-}
-
-impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset {
-	fn from((id, fun): (A, B)) -> MultiAsset {
-		MultiAsset { fun: fun.into(), id: id.into() }
-	}
-}
-
-impl MultiAsset {
-	pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
-		use Fungibility::*;
-		matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
-	}
-
-	pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
-		use Fungibility::*;
-		matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
-	}
-
-	/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
-	pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
-		self.id.prepend_with(prepend)
-	}
-
-	/// Mutate the location of the asset identifier if concrete, giving it the same location
-	/// relative to a `target` context. The local context is provided as `ancestry`.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		self.id.reanchor(target, ancestry)
-	}
-
-	/// Mutate the location of the asset identifier if concrete, giving it the same location
-	/// relative to a `target` context. The local context is provided as `ancestry`.
-	pub fn reanchored(
-		mut self,
-		target: &MultiLocation,
-		ancestry: &MultiLocation,
-	) -> Result<Self, ()> {
-		self.id.reanchor(target, ancestry)?;
-		Ok(self)
-	}
-
-	/// Returns true if `self` is a super-set of the given `inner`.
-	pub fn contains(&self, inner: &MultiAsset) -> bool {
-		use Fungibility::*;
-		if self.id == inner.id {
-			match (&self.fun, &inner.fun) {
-				(Fungible(a), Fungible(i)) if a >= i => return true,
-				(NonFungible(a), NonFungible(i)) if a == i => return true,
-				_ => (),
-			}
-		}
-		false
-	}
-}
-
-impl TryFrom<NewMultiAsset> for MultiAsset {
-	type Error = ();
-	fn try_from(new: NewMultiAsset) -> Result<Self, ()> {
-		Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
-	}
-}
-
-/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding,
-/// they must be sorted.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub struct MultiAssets(Vec<MultiAsset>);
-
-impl Decode for MultiAssets {
-	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
-		Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?)
-			.map_err(|()| "Out of order".into())
-	}
-}
-
-impl TryFrom<NewMultiAssets> for MultiAssets {
-	type Error = ();
-	fn try_from(new: NewMultiAssets) -> Result<Self, ()> {
-		let v = new
-			.into_inner()
-			.into_iter()
-			.map(MultiAsset::try_from)
-			.collect::<Result<Vec<_>, ()>>()?;
-		Ok(MultiAssets(v))
-	}
-}
-
-impl From<Vec<MultiAsset>> for MultiAssets {
-	fn from(mut assets: Vec<MultiAsset>) -> Self {
-		let mut res = Vec::with_capacity(assets.len());
-		if !assets.is_empty() {
-			assets.sort();
-			let mut iter = assets.into_iter();
-			if let Some(first) = iter.next() {
-				let last = iter.fold(first, |a, b| -> MultiAsset {
-					match (a, b) {
-						(
-							MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id },
-							MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id },
-						) if a_id == b_id => MultiAsset {
-							id: a_id,
-							fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
-						},
-						(
-							MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
-							MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id },
-						) if a_id == b_id && a_instance == b_instance =>
-							MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id },
-						(to_push, to_remember) => {
-							res.push(to_push);
-							to_remember
-						},
-					}
-				});
-				res.push(last);
-			}
-		}
-		Self(res)
-	}
-}
-
-impl<T: Into<MultiAsset>> From<T> for MultiAssets {
-	fn from(x: T) -> Self {
-		Self(vec![x.into()])
-	}
-}
-
-impl MultiAssets {
-	/// A new (empty) value.
-	pub fn new() -> Self {
-		Self(Vec::new())
-	}
-
-	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
-	/// and which contain no duplicates.
-	///
-	/// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates.
-	/// If you can't guarantee that `r` is sorted and deduplicated, then use
-	/// `From::<Vec<MultiAsset>>::from` which is infallible.
-	pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> {
-		if r.is_empty() {
-			return Ok(Self(Vec::new()))
-		}
-		r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> {
-			if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
-				Ok(b)
-			} else {
-				Err(())
-			}
-		})?;
-		Ok(Self(r))
-	}
-
-	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
-	/// and which contain no duplicates.
-	///
-	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
-	/// negligible-cost operation. Generally though you should avoid using it unless you have a
-	/// strict proof that `r` is valid.
-	#[cfg(test)]
-	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
-		Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
-	}
-	/// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted
-	/// and which contain no duplicates.
-	///
-	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
-	/// negligible-cost operation. Generally though you should avoid using it unless you have a
-	/// strict proof that `r` is valid.
-	///
-	/// In test mode, this checks anyway and panics on fail.
-	#[cfg(not(test))]
-	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self {
-		Self(r)
-	}
-
-	/// Add some asset onto the list, saturating. This is quite a laborious operation since it
-	/// maintains the ordering.
-	pub fn push(&mut self, a: MultiAsset) {
-		if let Fungibility::Fungible(ref amount) = a.fun {
-			for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
-				if let Fungibility::Fungible(ref mut balance) = asset.fun {
-					*balance = balance.saturating_add(*amount);
-					return
-				}
-			}
-		}
-		self.0.push(a);
-		self.0.sort();
-	}
-
-	/// Returns `true` if this definitely represents no asset.
-	pub fn is_none(&self) -> bool {
-		self.0.is_empty()
-	}
-
-	/// Returns true if `self` is a super-set of the given `inner`.
-	pub fn contains(&self, inner: &MultiAsset) -> bool {
-		self.0.iter().any(|i| i.contains(inner))
-	}
-
-	/// Consume `self` and return the inner vec.
-	pub fn drain(self) -> Vec<MultiAsset> {
-		self.0
-	}
-
-	/// Return a reference to the inner vec.
-	pub fn inner(&self) -> &Vec<MultiAsset> {
-		&self.0
-	}
-
-	/// Return the number of distinct asset instances contained.
-	pub fn len(&self) -> usize {
-		self.0.len()
-	}
-
-	/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
-	pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
-		self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
-	}
-
-	/// Mutate the location of the asset identifier if concrete, giving it the same location
-	/// relative to a `target` context. The local context is provided as `ancestry`.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		self.0.iter_mut().try_for_each(|i| i.reanchor(target, ancestry))
-	}
-
-	/// Return a reference to an item at a specific index or `None` if it doesn't exist.
-	pub fn get(&self, index: usize) -> Option<&MultiAsset> {
-		self.0.get(index)
-	}
-}
-
-/// Classification of whether an asset is fungible or not.
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum WildFungibility {
-	Fungible,
-	NonFungible,
-}
-
-impl TryFrom<NewWildFungibility> for WildFungibility {
-	type Error = ();
-	fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
-		use NewWildFungibility::*;
-		Ok(match value {
-			Fungible => Self::Fungible,
-			NonFungible => Self::NonFungible,
-		})
-	}
-}
-
-/// A wildcard representing a set of assets.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum WildMultiAsset {
-	/// All assets in the holding register, up to `usize` individual assets (different instances of
-	/// non-fungibles could be separate assets).
-	All,
-	/// All assets in the holding register of a given fungibility and ID. If operating on
-	/// non-fungibles, then a limit is provided for the maximum amount of matching instances.
-	AllOf { id: AssetId, fun: WildFungibility },
-}
-
-impl WildMultiAsset {
-	/// Returns true if `self` is a super-set of the given `inner`.
-	///
-	/// Typically, any wildcard is never contained in anything else, and a wildcard can contain any
-	/// other non-wildcard. For more details, see the implementation and tests.
-	pub fn contains(&self, inner: &MultiAsset) -> bool {
-		use WildMultiAsset::*;
-		match self {
-			AllOf { fun, id } => inner.fun.is_kind(*fun) && &inner.id == id,
-			All => true,
-		}
-	}
-
-	/// Mutate the location of the asset identifier if concrete, giving it the same location
-	/// relative to a `target` context. The local context is provided as `ancestry`.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		use WildMultiAsset::*;
-		match self {
-			AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()),
-			All => Ok(()),
-		}
-	}
-}
-
-impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset {
-	fn from((id, fun): (A, B)) -> WildMultiAsset {
-		WildMultiAsset::AllOf { fun: fun.into(), id: id.into() }
-	}
-}
-
-/// `MultiAsset` collection, either `MultiAssets` or a single wildcard.
-///
-/// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported
-/// in this implementation and will result in a decode error.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum MultiAssetFilter {
-	Definite(MultiAssets),
-	Wild(WildMultiAsset),
-}
-
-impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter {
-	fn from(x: T) -> Self {
-		Self::Wild(x.into())
-	}
-}
-
-impl From<MultiAsset> for MultiAssetFilter {
-	fn from(x: MultiAsset) -> Self {
-		Self::Definite(vec![x].into())
-	}
-}
-
-impl From<Vec<MultiAsset>> for MultiAssetFilter {
-	fn from(x: Vec<MultiAsset>) -> Self {
-		Self::Definite(x.into())
-	}
-}
-
-impl From<MultiAssets> for MultiAssetFilter {
-	fn from(x: MultiAssets) -> Self {
-		Self::Definite(x)
-	}
-}
-
-impl MultiAssetFilter {
-	/// Returns true if `self` is a super-set of the given `inner`.
-	///
-	/// Typically, any wildcard is never contained in anything else, and a wildcard can contain any
-	/// other non-wildcard. For more details, see the implementation and tests.
-	pub fn contains(&self, inner: &MultiAsset) -> bool {
-		match self {
-			MultiAssetFilter::Definite(ref assets) => assets.contains(inner),
-			MultiAssetFilter::Wild(ref wild) => wild.contains(inner),
-		}
-	}
-
-	/// Mutate the location of the asset identifier if concrete, giving it the same location
-	/// relative to a `target` context. The local context is provided as `ancestry`.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		match self {
-			MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry),
-			MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry),
-		}
-	}
-}
-
-impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
-	type Error = ();
-	fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
-		use NewWildMultiAsset::*;
-		Ok(match new {
-			AllOf { id, fun } | AllOfCounted { id, fun, .. } =>
-				Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
-			All | AllCounted(_) => Self::All,
-		})
-	}
-}
-
-impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
-	type Error = ();
-	fn try_from(old: NewMultiAssetFilter) -> Result<Self, ()> {
-		use NewMultiAssetFilter::*;
-		Ok(match old {
-			Definite(x) => Self::Definite(x.try_into()?),
-			Wild(x) => Self::Wild(x.try_into()?),
-		})
-	}
-}
diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs
deleted file mode 100644
index 9399ca6619c..00000000000
--- a/polkadot/xcm/src/v2/multilocation.rs
+++ /dev/null
@@ -1,1105 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Cross-Consensus Message format data structures.
-
-use super::Junction;
-use crate::v3::MultiLocation as NewMultiLocation;
-use codec::{Decode, Encode, MaxEncodedLen};
-use core::{mem, result};
-use scale_info::TypeInfo;
-
-/// A relative path between state-bearing consensus systems.
-///
-/// A location in a consensus system is defined as an *isolatable state machine* held within global
-/// consensus. The location in question need not have a sophisticated consensus algorithm of its
-/// own; a single account within Ethereum, for example, could be considered a location.
-///
-/// A very-much non-exhaustive list of types of location include:
-/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
-/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
-/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
-/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based
-///   Substrate chain.
-/// - An account.
-///
-/// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the
-/// relative path between two locations, and cannot generally be used to refer to a location
-/// universally. It is comprised of an integer number of parents specifying the number of times to
-/// "escape" upwards into the containing consensus system and then a number of *junctions*, each
-/// diving down and specifying some interior portion of state (which may be considered a
-/// "sub-consensus" system).
-///
-/// This specific `MultiLocation` implementation uses a `Junctions` datatype which is a Rust `enum`
-/// in order to make pattern matching easier. There are occasions where it is important to ensure
-/// that a value is strictly an interior location, in those cases, `Junctions` may be used.
-///
-/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system.
-#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub struct MultiLocation {
-	/// The number of parent junctions at the beginning of this `MultiLocation`.
-	pub parents: u8,
-	/// The interior (i.e. non-parent) junctions that this `MultiLocation` contains.
-	pub interior: Junctions,
-}
-
-impl Default for MultiLocation {
-	fn default() -> Self {
-		Self { parents: 0, interior: Junctions::Here }
-	}
-}
-
-/// A relative location which is constrained to be an interior location of the context.
-///
-/// See also `MultiLocation`.
-pub type InteriorMultiLocation = Junctions;
-
-impl MultiLocation {
-	/// Creates a new `MultiLocation` with the given number of parents and interior junctions.
-	pub fn new(parents: u8, junctions: Junctions) -> MultiLocation {
-		MultiLocation { parents, interior: junctions }
-	}
-
-	/// Consume `self` and return the equivalent `VersionedLocation` value.
-	pub fn versioned(self) -> crate::VersionedLocation {
-		self.into()
-	}
-
-	/// Creates a new `MultiLocation` with 0 parents and a `Here` interior.
-	///
-	/// The resulting `MultiLocation` can be interpreted as the "current consensus system".
-	pub const fn here() -> MultiLocation {
-		MultiLocation { parents: 0, interior: Junctions::Here }
-	}
-
-	/// Creates a new `MultiLocation` which evaluates to the parent context.
-	pub const fn parent() -> MultiLocation {
-		MultiLocation { parents: 1, interior: Junctions::Here }
-	}
-
-	/// Creates a new `MultiLocation` which evaluates to the grand parent context.
-	pub const fn grandparent() -> MultiLocation {
-		MultiLocation { parents: 2, interior: Junctions::Here }
-	}
-
-	/// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior.
-	pub const fn ancestor(parents: u8) -> MultiLocation {
-		MultiLocation { parents, interior: Junctions::Here }
-	}
-
-	/// Whether the `MultiLocation` has no parents and has a `Here` interior.
-	pub const fn is_here(&self) -> bool {
-		self.parents == 0 && self.interior.len() == 0
-	}
-
-	/// Return a reference to the interior field.
-	pub fn interior(&self) -> &Junctions {
-		&self.interior
-	}
-
-	/// Return a mutable reference to the interior field.
-	pub fn interior_mut(&mut self) -> &mut Junctions {
-		&mut self.interior
-	}
-
-	/// Returns the number of `Parent` junctions at the beginning of `self`.
-	pub const fn parent_count(&self) -> u8 {
-		self.parents
-	}
-
-	/// Returns boolean indicating whether `self` contains only the specified amount of
-	/// parents and no interior junctions.
-	pub const fn contains_parents_only(&self, count: u8) -> bool {
-		matches!(self.interior, Junctions::Here) && self.parents == count
-	}
-
-	/// Returns the number of parents and junctions in `self`.
-	pub const fn len(&self) -> usize {
-		self.parent_count() as usize + self.interior.len()
-	}
-
-	/// Returns the first interior junction, or `None` if the location is empty or contains only
-	/// parents.
-	pub fn first_interior(&self) -> Option<&Junction> {
-		self.interior.first()
-	}
-
-	/// Returns last junction, or `None` if the location is empty or contains only parents.
-	pub fn last(&self) -> Option<&Junction> {
-		self.interior.last()
-	}
-
-	/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
-	/// and the first element (second item in tuple) or `None` if it was empty.
-	pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) {
-		let MultiLocation { parents, interior: junctions } = self;
-		let (suffix, first) = junctions.split_first();
-		let multilocation = MultiLocation { parents, interior: suffix };
-		(multilocation, first)
-	}
-
-	/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
-	/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
-	/// contains parents.
-	pub fn split_last_interior(self) -> (MultiLocation, Option<Junction>) {
-		let MultiLocation { parents, interior: junctions } = self;
-		let (prefix, last) = junctions.split_last();
-		let multilocation = MultiLocation { parents, interior: prefix };
-		(multilocation, last)
-	}
-
-	/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
-	/// case of overflow.
-	pub fn push_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
-		self.interior.push(new)
-	}
-
-	/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
-	/// case of overflow.
-	pub fn push_front_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
-		self.interior.push_front(new)
-	}
-
-	/// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with
-	/// the original value of `self` in case of overflow.
-	pub fn pushed_with_interior(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
-		match self.interior.pushed_with(new) {
-			Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
-			Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
-		}
-	}
-
-	/// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the
-	/// original value of `self` in case of overflow.
-	pub fn pushed_front_with_interior(
-		self,
-		new: Junction,
-	) -> result::Result<Self, (Self, Junction)> {
-		match self.interior.pushed_front_with(new) {
-			Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
-			Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
-		}
-	}
-
-	/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
-	/// does not contain that many elements.
-	pub fn at(&self, i: usize) -> Option<&Junction> {
-		let num_parents = self.parents as usize;
-		if i < num_parents {
-			return None
-		}
-		self.interior.at(i - num_parents)
-	}
-
-	/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
-	/// parent or if it doesn't contain that many elements.
-	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
-		let num_parents = self.parents as usize;
-		if i < num_parents {
-			return None
-		}
-		self.interior.at_mut(i - num_parents)
-	}
-
-	/// Decrements the parent count by 1.
-	pub fn dec_parent(&mut self) {
-		self.parents = self.parents.saturating_sub(1);
-	}
-
-	/// Removes the first interior junction from `self`, returning it
-	/// (or `None` if it was empty or if `self` contains only parents).
-	pub fn take_first_interior(&mut self) -> Option<Junction> {
-		self.interior.take_first()
-	}
-
-	/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
-	/// `self` only contains parents).
-	pub fn take_last(&mut self) -> Option<Junction> {
-		self.interior.take_last()
-	}
-
-	/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
-	/// the junctions of `prefix` and that it has a single `Junction` item following.
-	/// If so, returns a reference to this `Junction` item.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
-	/// let mut m = MultiLocation::new(1, [PalletInstance(3), OnlyChild].into());
-	/// assert_eq!(
-	///     m.match_and_split(&MultiLocation::new(1, [PalletInstance(3)].into())),
-	///     Some(&OnlyChild),
-	/// );
-	/// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None);
-	/// ```
-	pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
-		if self.parents != prefix.parents {
-			return None
-		}
-		self.interior.match_and_split(&prefix.interior)
-	}
-
-	/// Returns whether `self` has the same number of parents as `prefix` and its junctions begins
-	/// with the junctions of `prefix`.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
-	/// let m = MultiLocation::new(1, [PalletInstance(3), OnlyChild, OnlyChild].into());
-	/// assert!(m.starts_with(&MultiLocation::new(1, [PalletInstance(3)].into())));
-	/// assert!(!m.starts_with(&MultiLocation::new(1, [GeneralIndex(99)].into())));
-	/// assert!(!m.starts_with(&MultiLocation::new(0, [PalletInstance(3)].into())));
-	/// ```
-	pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
-		if self.parents != prefix.parents {
-			return false
-		}
-		self.interior.starts_with(&prefix.interior)
-	}
-
-	/// Mutate `self` so that it is suffixed with `suffix`.
-	///
-	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
-	/// let mut m = MultiLocation::new(1, [Parachain(21)].into());
-	/// assert_eq!(m.append_with([PalletInstance(3)].into()), Ok(()));
-	/// assert_eq!(m, MultiLocation::new(1, [Parachain(21), PalletInstance(3)].into()));
-	/// ```
-	pub fn append_with(&mut self, suffix: Junctions) -> Result<(), Junctions> {
-		if self.interior.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
-			return Err(suffix)
-		}
-		for j in suffix.into_iter() {
-			self.interior.push(j).expect("Already checked the sum of the len()s; qed")
-		}
-		Ok(())
-	}
-
-	/// Mutate `self` so that it is prefixed with `prefix`.
-	///
-	/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
-	/// let mut m = MultiLocation::new(2, [PalletInstance(3)].into());
-	/// assert_eq!(m.prepend_with(MultiLocation::new(1, [Parachain(21), OnlyChild].into())), Ok(()));
-	/// assert_eq!(m, MultiLocation::new(1, [PalletInstance(3)].into()));
-	/// ```
-	pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> {
-		//     prefix     self (suffix)
-		// P .. P I .. I  p .. p i .. i
-		let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
-		let final_interior = self.interior.len().saturating_add(prepend_interior);
-		if final_interior > MAX_JUNCTIONS {
-			return Err(prefix)
-		}
-		let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
-		let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
-		if final_parents > 255 {
-			return Err(prefix)
-		}
-
-		// cancel out the final item on the prefix interior for one of the suffix's parents.
-		while self.parents > 0 && prefix.take_last().is_some() {
-			self.dec_parent();
-		}
-
-		// now we have either removed all suffix's parents or prefix interior.
-		// this means we can combine the prefix's and suffix's remaining parents/interior since
-		// we know that with at least one empty, the overall order will be respected:
-		//     prefix     self (suffix)
-		// P .. P   (I)   p .. p i .. i => P + p .. (no I) i
-		//  -- or --
-		// P .. P I .. I    (p)  i .. i => P (no p) .. I + i
-
-		self.parents = self.parents.saturating_add(prefix.parents);
-		for j in prefix.interior.into_iter().rev() {
-			self.push_front_interior(j)
-				.expect("final_interior no greater than MAX_JUNCTIONS; qed");
-		}
-		Ok(())
-	}
-
-	/// Consume `self` and return the value representing the same location from the point of view
-	/// of `target`. The context of `self` is provided as `ancestry`.
-	///
-	/// Returns an `Err` with the unmodified `self` in the case of error.
-	pub fn reanchored(
-		mut self,
-		target: &MultiLocation,
-		ancestry: &MultiLocation,
-	) -> Result<Self, Self> {
-		match self.reanchor(target, ancestry) {
-			Ok(()) => Ok(self),
-			Err(()) => Err(self),
-		}
-	}
-
-	/// Mutate `self` so that it represents the same location from the point of view of `target`.
-	/// The context of `self` is provided as `ancestry`.
-	///
-	/// Does not modify `self` in case of overflow.
-	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
-		// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
-
-		// 1. Use our `ancestry` to figure out how the `target` would address us.
-		let inverted_target = ancestry.inverted(target)?;
-
-		// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
-		// `target`.
-		self.prepend_with(inverted_target).map_err(|_| ())?;
-
-		// 3. Given that we know some of `target` ancestry, ensure that any parents in `self` are
-		// strictly needed.
-		self.simplify(target.interior());
-
-		Ok(())
-	}
-
-	/// Treating `self` as a context, determine how it would be referenced by a `target` location.
-	pub fn inverted(&self, target: &MultiLocation) -> Result<MultiLocation, ()> {
-		use Junction::OnlyChild;
-		let mut ancestry = self.clone();
-		let mut junctions = Junctions::Here;
-		for _ in 0..target.parent_count() {
-			junctions = junctions
-				.pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild))
-				.map_err(|_| ())?;
-		}
-		let parents = target.interior().len() as u8;
-		Ok(MultiLocation::new(parents, junctions))
-	}
-
-	/// Remove any unneeded parents/junctions in `self` based on the given context it will be
-	/// interpreted in.
-	pub fn simplify(&mut self, context: &Junctions) {
-		if context.len() < self.parents as usize {
-			// Not enough context
-			return
-		}
-		while self.parents > 0 {
-			let maybe = context.at(context.len() - (self.parents as usize));
-			match (self.interior.first(), maybe) {
-				(Some(i), Some(j)) if i == j => {
-					self.interior.take_first();
-					self.parents -= 1;
-				},
-				_ => break,
-			}
-		}
-	}
-}
-
-impl TryFrom<NewMultiLocation> for MultiLocation {
-	type Error = ();
-	fn try_from(x: NewMultiLocation) -> result::Result<Self, ()> {
-		Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
-	}
-}
-
-/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct Parent;
-impl From<Parent> for MultiLocation {
-	fn from(_: Parent) -> Self {
-		MultiLocation { parents: 1, interior: Junctions::Here }
-	}
-}
-
-/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner
-/// interior.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct ParentThen(pub Junctions);
-impl From<ParentThen> for MultiLocation {
-	fn from(ParentThen(interior): ParentThen) -> Self {
-		MultiLocation { parents: 1, interior }
-	}
-}
-
-/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct Ancestor(pub u8);
-impl From<Ancestor> for MultiLocation {
-	fn from(Ancestor(parents): Ancestor) -> Self {
-		MultiLocation { parents, interior: Junctions::Here }
-	}
-}
-
-/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the
-/// inner interior.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct AncestorThen<Interior>(pub u8, pub Interior);
-impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
-	fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
-		MultiLocation { parents, interior: interior.into() }
-	}
-}
-
-xcm_procedural::impl_conversion_functions_for_multilocation_v2!();
-xcm_procedural::impl_conversion_functions_for_junctions_v2!();
-
-/// Maximum number of `Junction`s that a `Junctions` can contain.
-const MAX_JUNCTIONS: usize = 8;
-
-/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
-/// implementation uses a Rust `enum` in order to make pattern matching easier.
-///
-/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for
-/// instructions on constructing parent junctions.
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Junctions {
-	/// The interpreting consensus system.
-	Here,
-	/// A relative path comprising 1 junction.
-	X1(Junction),
-	/// A relative path comprising 2 junctions.
-	X2(Junction, Junction),
-	/// A relative path comprising 3 junctions.
-	X3(Junction, Junction, Junction),
-	/// A relative path comprising 4 junctions.
-	X4(Junction, Junction, Junction, Junction),
-	/// A relative path comprising 5 junctions.
-	X5(Junction, Junction, Junction, Junction, Junction),
-	/// A relative path comprising 6 junctions.
-	X6(Junction, Junction, Junction, Junction, Junction, Junction),
-	/// A relative path comprising 7 junctions.
-	X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
-	/// A relative path comprising 8 junctions.
-	X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
-}
-
-pub struct JunctionsIterator(Junctions);
-impl Iterator for JunctionsIterator {
-	type Item = Junction;
-	fn next(&mut self) -> Option<Junction> {
-		self.0.take_first()
-	}
-}
-
-impl DoubleEndedIterator for JunctionsIterator {
-	fn next_back(&mut self) -> Option<Junction> {
-		self.0.take_last()
-	}
-}
-
-pub struct JunctionsRefIterator<'a> {
-	junctions: &'a Junctions,
-	next: usize,
-	back: usize,
-}
-
-impl<'a> Iterator for JunctionsRefIterator<'a> {
-	type Item = &'a Junction;
-	fn next(&mut self) -> Option<&'a Junction> {
-		if self.next.saturating_add(self.back) >= self.junctions.len() {
-			return None
-		}
-
-		let result = self.junctions.at(self.next);
-		self.next += 1;
-		result
-	}
-}
-
-impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
-	fn next_back(&mut self) -> Option<&'a Junction> {
-		let next_back = self.back.saturating_add(1);
-		// checked_sub here, because if the result is less than 0, we end iteration
-		let index = self.junctions.len().checked_sub(next_back)?;
-		if self.next > index {
-			return None
-		}
-		self.back = next_back;
-
-		self.junctions.at(index)
-	}
-}
-
-impl<'a> IntoIterator for &'a Junctions {
-	type Item = &'a Junction;
-	type IntoIter = JunctionsRefIterator<'a>;
-	fn into_iter(self) -> Self::IntoIter {
-		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
-	}
-}
-
-impl IntoIterator for Junctions {
-	type Item = Junction;
-	type IntoIter = JunctionsIterator;
-	fn into_iter(self) -> Self::IntoIter {
-		JunctionsIterator(self)
-	}
-}
-
-impl Junctions {
-	/// Convert `self` into a `MultiLocation` containing 0 parents.
-	///
-	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
-	pub const fn into(self) -> MultiLocation {
-		MultiLocation { parents: 0, interior: self }
-	}
-
-	/// Convert `self` into a `MultiLocation` containing `n` parents.
-	///
-	/// Similar to `Self::into`, with the added ability to specify the number of parent junctions.
-	pub const fn into_exterior(self, n: u8) -> MultiLocation {
-		MultiLocation { parents: n, interior: self }
-	}
-
-	/// Returns first junction, or `None` if the location is empty.
-	pub fn first(&self) -> Option<&Junction> {
-		match &self {
-			Junctions::Here => None,
-			Junctions::X1(ref a) => Some(a),
-			Junctions::X2(ref a, ..) => Some(a),
-			Junctions::X3(ref a, ..) => Some(a),
-			Junctions::X4(ref a, ..) => Some(a),
-			Junctions::X5(ref a, ..) => Some(a),
-			Junctions::X6(ref a, ..) => Some(a),
-			Junctions::X7(ref a, ..) => Some(a),
-			Junctions::X8(ref a, ..) => Some(a),
-		}
-	}
-
-	/// Returns last junction, or `None` if the location is empty.
-	pub fn last(&self) -> Option<&Junction> {
-		match &self {
-			Junctions::Here => None,
-			Junctions::X1(ref a) => Some(a),
-			Junctions::X2(.., ref a) => Some(a),
-			Junctions::X3(.., ref a) => Some(a),
-			Junctions::X4(.., ref a) => Some(a),
-			Junctions::X5(.., ref a) => Some(a),
-			Junctions::X6(.., ref a) => Some(a),
-			Junctions::X7(.., ref a) => Some(a),
-			Junctions::X8(.., ref a) => Some(a),
-		}
-	}
-
-	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
-	/// first element (second item in tuple) or `None` if it was empty.
-	pub fn split_first(self) -> (Junctions, Option<Junction>) {
-		match self {
-			Junctions::Here => (Junctions::Here, None),
-			Junctions::X1(a) => (Junctions::Here, Some(a)),
-			Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
-			Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
-			Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
-			Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
-			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
-			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
-			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
-		}
-	}
-
-	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
-	/// last element (second item in tuple) or `None` if it was empty.
-	pub fn split_last(self) -> (Junctions, Option<Junction>) {
-		match self {
-			Junctions::Here => (Junctions::Here, None),
-			Junctions::X1(a) => (Junctions::Here, Some(a)),
-			Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
-			Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
-			Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
-			Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
-			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
-			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
-			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
-		}
-	}
-
-	/// Removes the first element from `self`, returning it (or `None` if it was empty).
-	pub fn take_first(&mut self) -> Option<Junction> {
-		let mut d = Junctions::Here;
-		mem::swap(&mut *self, &mut d);
-		let (tail, head) = d.split_first();
-		*self = tail;
-		head
-	}
-
-	/// Removes the last element from `self`, returning it (or `None` if it was empty).
-	pub fn take_last(&mut self) -> Option<Junction> {
-		let mut d = Junctions::Here;
-		mem::swap(&mut *self, &mut d);
-		let (head, tail) = d.split_last();
-		*self = head;
-		tail
-	}
-
-	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
-	pub fn push(&mut self, new: Junction) -> result::Result<(), Junction> {
-		let mut dummy = Junctions::Here;
-		mem::swap(self, &mut dummy);
-		match dummy.pushed_with(new) {
-			Ok(s) => {
-				*self = s;
-				Ok(())
-			},
-			Err((s, j)) => {
-				*self = s;
-				Err(j)
-			},
-		}
-	}
-
-	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
-	pub fn push_front(&mut self, new: Junction) -> result::Result<(), Junction> {
-		let mut dummy = Junctions::Here;
-		mem::swap(self, &mut dummy);
-		match dummy.pushed_front_with(new) {
-			Ok(s) => {
-				*self = s;
-				Ok(())
-			},
-			Err((s, j)) => {
-				*self = s;
-				Err(j)
-			},
-		}
-	}
-
-	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
-	/// original value of `self` and `new` in case of overflow.
-	pub fn pushed_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
-		Ok(match self {
-			Junctions::Here => Junctions::X1(new),
-			Junctions::X1(a) => Junctions::X2(a, new),
-			Junctions::X2(a, b) => Junctions::X3(a, b, new),
-			Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
-			Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
-			Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
-			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
-			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
-			s => Err((s, new))?,
-		})
-	}
-
-	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
-	/// original value of `self` and `new` in case of overflow.
-	pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
-		Ok(match self {
-			Junctions::Here => Junctions::X1(new),
-			Junctions::X1(a) => Junctions::X2(new, a),
-			Junctions::X2(a, b) => Junctions::X3(new, a, b),
-			Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
-			Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
-			Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
-			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
-			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
-			s => Err((s, new))?,
-		})
-	}
-
-	/// Returns the number of junctions in `self`.
-	pub const fn len(&self) -> usize {
-		match &self {
-			Junctions::Here => 0,
-			Junctions::X1(..) => 1,
-			Junctions::X2(..) => 2,
-			Junctions::X3(..) => 3,
-			Junctions::X4(..) => 4,
-			Junctions::X5(..) => 5,
-			Junctions::X6(..) => 6,
-			Junctions::X7(..) => 7,
-			Junctions::X8(..) => 8,
-		}
-	}
-
-	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
-	/// elements.
-	pub fn at(&self, i: usize) -> Option<&Junction> {
-		Some(match (i, self) {
-			(0, Junctions::X1(ref a)) => a,
-			(0, Junctions::X2(ref a, ..)) => a,
-			(0, Junctions::X3(ref a, ..)) => a,
-			(0, Junctions::X4(ref a, ..)) => a,
-			(0, Junctions::X5(ref a, ..)) => a,
-			(0, Junctions::X6(ref a, ..)) => a,
-			(0, Junctions::X7(ref a, ..)) => a,
-			(0, Junctions::X8(ref a, ..)) => a,
-			(1, Junctions::X2(_, ref a)) => a,
-			(1, Junctions::X3(_, ref a, ..)) => a,
-			(1, Junctions::X4(_, ref a, ..)) => a,
-			(1, Junctions::X5(_, ref a, ..)) => a,
-			(1, Junctions::X6(_, ref a, ..)) => a,
-			(1, Junctions::X7(_, ref a, ..)) => a,
-			(1, Junctions::X8(_, ref a, ..)) => a,
-			(2, Junctions::X3(_, _, ref a)) => a,
-			(2, Junctions::X4(_, _, ref a, ..)) => a,
-			(2, Junctions::X5(_, _, ref a, ..)) => a,
-			(2, Junctions::X6(_, _, ref a, ..)) => a,
-			(2, Junctions::X7(_, _, ref a, ..)) => a,
-			(2, Junctions::X8(_, _, ref a, ..)) => a,
-			(3, Junctions::X4(_, _, _, ref a)) => a,
-			(3, Junctions::X5(_, _, _, ref a, ..)) => a,
-			(3, Junctions::X6(_, _, _, ref a, ..)) => a,
-			(3, Junctions::X7(_, _, _, ref a, ..)) => a,
-			(3, Junctions::X8(_, _, _, ref a, ..)) => a,
-			(4, Junctions::X5(_, _, _, _, ref a)) => a,
-			(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
-			(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
-			(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
-			(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
-			(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
-			(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
-			(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
-			(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
-			(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
-			_ => return None,
-		})
-	}
-
-	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
-	/// contain that many elements.
-	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
-		Some(match (i, self) {
-			(0, Junctions::X1(ref mut a)) => a,
-			(0, Junctions::X2(ref mut a, ..)) => a,
-			(0, Junctions::X3(ref mut a, ..)) => a,
-			(0, Junctions::X4(ref mut a, ..)) => a,
-			(0, Junctions::X5(ref mut a, ..)) => a,
-			(0, Junctions::X6(ref mut a, ..)) => a,
-			(0, Junctions::X7(ref mut a, ..)) => a,
-			(0, Junctions::X8(ref mut a, ..)) => a,
-			(1, Junctions::X2(_, ref mut a)) => a,
-			(1, Junctions::X3(_, ref mut a, ..)) => a,
-			(1, Junctions::X4(_, ref mut a, ..)) => a,
-			(1, Junctions::X5(_, ref mut a, ..)) => a,
-			(1, Junctions::X6(_, ref mut a, ..)) => a,
-			(1, Junctions::X7(_, ref mut a, ..)) => a,
-			(1, Junctions::X8(_, ref mut a, ..)) => a,
-			(2, Junctions::X3(_, _, ref mut a)) => a,
-			(2, Junctions::X4(_, _, ref mut a, ..)) => a,
-			(2, Junctions::X5(_, _, ref mut a, ..)) => a,
-			(2, Junctions::X6(_, _, ref mut a, ..)) => a,
-			(2, Junctions::X7(_, _, ref mut a, ..)) => a,
-			(2, Junctions::X8(_, _, ref mut a, ..)) => a,
-			(3, Junctions::X4(_, _, _, ref mut a)) => a,
-			(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
-			(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
-			(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
-			(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
-			(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
-			(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
-			(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
-			(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
-			(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
-			(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
-			(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
-			(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
-			(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
-			(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
-			_ => return None,
-		})
-	}
-
-	/// Returns a reference iterator over the junctions.
-	pub fn iter(&self) -> JunctionsRefIterator {
-		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
-	}
-
-	/// Returns a reference iterator over the junctions in reverse.
-	#[deprecated(note = "Please use iter().rev()")]
-	pub fn iter_rev(&self) -> impl Iterator + '_ {
-		self.iter().rev()
-	}
-
-	/// Consumes `self` and returns an iterator over the junctions in reverse.
-	#[deprecated(note = "Please use into_iter().rev()")]
-	pub fn into_iter_rev(self) -> impl Iterator {
-		self.into_iter().rev()
-	}
-
-	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
-	/// If so, returns a reference to this `Junction` item.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*};
-	/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
-	/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
-	/// assert_eq!(m.match_and_split(&X1(Parachain(2))), None);
-	/// ```
-	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
-		if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
-			return None
-		}
-		self.at(prefix.len())
-	}
-
-	/// Returns whether `self` begins with or is equal to `prefix`.
-	///
-	/// # Example
-	/// ```rust
-	/// # use staging_xcm::v2::{Junctions::*, Junction::*};
-	/// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild);
-	/// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3))));
-	/// assert!(j.starts_with(&j));
-	/// assert!(j.starts_with(&X1(Parachain(2))));
-	/// assert!(!j.starts_with(&X1(Parachain(999))));
-	/// assert!(!j.starts_with(&X4(Parachain(2), PalletInstance(3), OnlyChild, OnlyChild)));
-	/// ```
-	pub fn starts_with(&self, prefix: &Junctions) -> bool {
-		if self.len() < prefix.len() {
-			return false
-		}
-		prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
-	}
-}
-
-impl TryFrom<MultiLocation> for Junctions {
-	type Error = ();
-	fn try_from(x: MultiLocation) -> result::Result<Self, ()> {
-		if x.parents > 0 {
-			Err(())
-		} else {
-			Ok(x.interior)
-		}
-	}
-}
-
-#[cfg(test)]
-mod tests {
-	use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
-	use crate::opaque::v2::{Junction::*, NetworkId::*};
-	use codec::{Decode, Encode};
-
-	#[test]
-	fn inverted_works() {
-		let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into();
-		let target = (Parent, PalletInstance(69)).into();
-		let expected = (Parent, PalletInstance(42)).into();
-		let inverted = ancestry.inverted(&target).unwrap();
-		assert_eq!(inverted, expected);
-
-		let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
-		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
-		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
-		let inverted = ancestry.inverted(&target).unwrap();
-		assert_eq!(inverted, expected);
-	}
-
-	#[test]
-	fn simplify_basic_works() {
-		let mut location: MultiLocation =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		let context = X2(Parachain(1000), PalletInstance(42));
-		let expected = GeneralIndex(69).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-
-		let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
-		let context = X1(PalletInstance(42));
-		let expected = GeneralIndex(69).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-
-		let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
-		let context = X2(Parachain(1000), PalletInstance(42));
-		let expected = GeneralIndex(69).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-
-		let mut location: MultiLocation =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
-		let expected = GeneralIndex(69).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-	}
-
-	#[test]
-	fn simplify_incompatible_location_fails() {
-		let mut location: MultiLocation =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
-		let expected =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-
-		let mut location: MultiLocation =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		let context = X1(Parachain(1000));
-		let expected =
-			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
-		location.simplify(&context);
-		assert_eq!(location, expected);
-	}
-
-	#[test]
-	fn reanchor_works() {
-		let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
-		let ancestry = Parachain(2000).into();
-		let target = (Parent, Parachain(1000)).into();
-		let expected = GeneralIndex(42).into();
-		id.reanchor(&target, &ancestry).unwrap();
-		assert_eq!(id, expected);
-	}
-
-	#[test]
-	fn encode_and_decode_works() {
-		let m = MultiLocation {
-			parents: 1,
-			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
-		};
-		let encoded = m.encode();
-		assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
-		let decoded = MultiLocation::decode(&mut &encoded[..]);
-		assert_eq!(decoded, Ok(m));
-	}
-
-	#[test]
-	fn match_and_split_works() {
-		let m = MultiLocation {
-			parents: 1,
-			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
-		};
-		assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None);
-		assert_eq!(
-			m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }),
-			Some(&AccountIndex64 { network: Any, index: 23 })
-		);
-		assert_eq!(m.match_and_split(&m), None);
-	}
-
-	#[test]
-	fn starts_with_works() {
-		let full: MultiLocation =
-			(Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into();
-		let identity: MultiLocation = full.clone();
-		let prefix: MultiLocation = (Parent, Parachain(1000)).into();
-		let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into();
-		let wrong_account: MultiLocation =
-			(Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into();
-		let no_parents: MultiLocation = (Parachain(1000)).into();
-		let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into();
-
-		assert!(full.starts_with(&identity));
-		assert!(full.starts_with(&prefix));
-		assert!(!full.starts_with(&wrong_parachain));
-		assert!(!full.starts_with(&wrong_account));
-		assert!(!full.starts_with(&no_parents));
-		assert!(!full.starts_with(&too_many_parents));
-	}
-
-	#[test]
-	fn append_with_works() {
-		let acc = AccountIndex64 { network: Any, index: 23 };
-		let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) };
-		assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(()));
-		assert_eq!(
-			m,
-			MultiLocation {
-				parents: 1,
-				interior: X3(Parachain(42), PalletInstance(3), acc.clone())
-			}
-		);
-
-		// cannot append to create overly long multilocation
-		let acc = AccountIndex64 { network: Any, index: 23 };
-		let m = MultiLocation {
-			parents: 254,
-			interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild),
-		};
-		let suffix = X4(PalletInstance(3), acc.clone(), OnlyChild, OnlyChild);
-		assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
-	}
-
-	#[test]
-	fn prepend_with_works() {
-		let mut m = MultiLocation {
-			parents: 1,
-			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
-		};
-		assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(()));
-		assert_eq!(
-			m,
-			MultiLocation {
-				parents: 1,
-				interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 })
-			}
-		);
-
-		// cannot prepend to create overly long multilocation
-		let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) };
-		let prefix = MultiLocation { parents: 2, interior: Here };
-		assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
-
-		let prefix = MultiLocation { parents: 1, interior: Here };
-		assert_eq!(m.prepend_with(prefix), Ok(()));
-		assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) });
-	}
-
-	#[test]
-	fn double_ended_ref_iteration_works() {
-		let m = X3(Parachain(1000), Parachain(3), PalletInstance(5));
-		let mut iter = m.iter();
-
-		let first = iter.next().unwrap();
-		assert_eq!(first, &Parachain(1000));
-		let third = iter.next_back().unwrap();
-		assert_eq!(third, &PalletInstance(5));
-		let second = iter.next_back().unwrap();
-		assert_eq!(iter.next(), None);
-		assert_eq!(iter.next_back(), None);
-		assert_eq!(second, &Parachain(3));
-
-		let res = Here
-			.pushed_with(first.clone())
-			.unwrap()
-			.pushed_with(second.clone())
-			.unwrap()
-			.pushed_with(third.clone())
-			.unwrap();
-		assert_eq!(m, res);
-
-		// make sure there's no funny business with the 0 indexing
-		let m = Here;
-		let mut iter = m.iter();
-
-		assert_eq!(iter.next(), None);
-		assert_eq!(iter.next_back(), None);
-	}
-
-	#[test]
-	fn conversion_from_other_types_works() {
-		fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
-
-		takes_multilocation(Parent);
-		takes_multilocation(Here);
-		takes_multilocation(X1(Parachain(42)));
-		takes_multilocation((255, PalletInstance(8)));
-		takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
-		takes_multilocation((Ancestor(2), Here));
-		takes_multilocation(AncestorThen(
-			3,
-			X2(Parachain(43), AccountIndex64 { network: Any, index: 155 }),
-		));
-		takes_multilocation((Parent, AccountId32 { network: Any, id: [0; 32] }));
-		takes_multilocation((Parent, Here));
-		takes_multilocation(ParentThen(X1(Parachain(75))));
-		takes_multilocation([Parachain(100), PalletInstance(3)]);
-	}
-}
diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs
deleted file mode 100644
index 815495b8127..00000000000
--- a/polkadot/xcm/src/v2/traits.rs
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Cross-Consensus Message format data structures.
-
-use crate::v3::Error as NewError;
-use codec::{Decode, Encode};
-use core::result;
-use scale_info::TypeInfo;
-
-use super::*;
-
-// A simple trait to get the weight of some object.
-pub trait GetWeight<W> {
-	fn weight(&self) -> sp_weights::Weight;
-}
-
-#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Error {
-	// Errors that happen due to instructions being executed. These alone are defined in the
-	// XCM specification.
-	/// An arithmetic overflow happened.
-	#[codec(index = 0)]
-	Overflow,
-	/// The instruction is intentionally unsupported.
-	#[codec(index = 1)]
-	Unimplemented,
-	/// Origin Register does not contain a value value for a reserve transfer notification.
-	#[codec(index = 2)]
-	UntrustedReserveLocation,
-	/// Origin Register does not contain a value value for a teleport notification.
-	#[codec(index = 3)]
-	UntrustedTeleportLocation,
-	/// `MultiLocation` value too large to descend further.
-	#[codec(index = 4)]
-	MultiLocationFull,
-	/// `MultiLocation` value ascend more parents than known ancestors of local location.
-	#[codec(index = 5)]
-	MultiLocationNotInvertible,
-	/// The Origin Register does not contain a valid value for instruction.
-	#[codec(index = 6)]
-	BadOrigin,
-	/// The location parameter is not a valid value for the instruction.
-	#[codec(index = 7)]
-	InvalidLocation,
-	/// The given asset is not handled.
-	#[codec(index = 8)]
-	AssetNotFound,
-	/// An asset transaction (like withdraw or deposit) failed (typically due to type conversions).
-	#[codec(index = 9)]
-	FailedToTransactAsset(#[codec(skip)] &'static str),
-	/// An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights.
-	#[codec(index = 10)]
-	NotWithdrawable,
-	/// An asset cannot be deposited under the ownership of a particular location.
-	#[codec(index = 11)]
-	LocationCannotHold,
-	/// Attempt to send a message greater than the maximum supported by the transport protocol.
-	#[codec(index = 12)]
-	ExceedsMaxMessageSize,
-	/// The given message cannot be translated into a format supported by the destination.
-	#[codec(index = 13)]
-	DestinationUnsupported,
-	/// Destination is routable, but there is some issue with the transport mechanism.
-	#[codec(index = 14)]
-	Transport(#[codec(skip)] &'static str),
-	/// Destination is known to be unroutable.
-	#[codec(index = 15)]
-	Unroutable,
-	/// Used by `ClaimAsset` when the given claim could not be recognized/found.
-	#[codec(index = 16)]
-	UnknownClaim,
-	/// Used by `Transact` when the functor cannot be decoded.
-	#[codec(index = 17)]
-	FailedToDecode,
-	/// Used by `Transact` to indicate that the given weight limit could be breached by the
-	/// functor.
-	#[codec(index = 18)]
-	MaxWeightInvalid,
-	/// Used by `BuyExecution` when the Holding Register does not contain payable fees.
-	#[codec(index = 19)]
-	NotHoldingFees,
-	/// Used by `BuyExecution` when the fees declared to purchase weight are insufficient.
-	#[codec(index = 20)]
-	TooExpensive,
-	/// Used by the `Trap` instruction to force an error intentionally. Its code is included.
-	#[codec(index = 21)]
-	Trap(u64),
-
-	// Errors that happen prior to instructions being executed. These fall outside of the XCM
-	// spec.
-	/// XCM version not able to be handled.
-	UnhandledXcmVersion,
-	/// Execution of the XCM would potentially result in a greater weight used than weight limit.
-	WeightLimitReached(Weight),
-	/// The XCM did not pass the barrier condition for execution.
-	///
-	/// The barrier condition differs on different chains and in different circumstances, but
-	/// generally it means that the conditions surrounding the message were not such that the chain
-	/// considers the message worth spending time executing. Since most chains lift the barrier to
-	/// execution on appropriate payment, presentation of an NFT voucher, or based on the message
-	/// origin, it means that none of those were the case.
-	Barrier,
-	/// The weight of an XCM message is not computable ahead of execution.
-	WeightNotComputable,
-}
-
-impl TryFrom<NewError> for Error {
-	type Error = ();
-	fn try_from(new_error: NewError) -> result::Result<Error, ()> {
-		use NewError::*;
-		Ok(match new_error {
-			Overflow => Self::Overflow,
-			Unimplemented => Self::Unimplemented,
-			UntrustedReserveLocation => Self::UntrustedReserveLocation,
-			UntrustedTeleportLocation => Self::UntrustedTeleportLocation,
-			LocationFull => Self::MultiLocationFull,
-			LocationNotInvertible => Self::MultiLocationNotInvertible,
-			BadOrigin => Self::BadOrigin,
-			InvalidLocation => Self::InvalidLocation,
-			AssetNotFound => Self::AssetNotFound,
-			FailedToTransactAsset(s) => Self::FailedToTransactAsset(s),
-			NotWithdrawable => Self::NotWithdrawable,
-			LocationCannotHold => Self::LocationCannotHold,
-			ExceedsMaxMessageSize => Self::ExceedsMaxMessageSize,
-			DestinationUnsupported => Self::DestinationUnsupported,
-			Transport(s) => Self::Transport(s),
-			Unroutable => Self::Unroutable,
-			UnknownClaim => Self::UnknownClaim,
-			FailedToDecode => Self::FailedToDecode,
-			MaxWeightInvalid => Self::MaxWeightInvalid,
-			NotHoldingFees => Self::NotHoldingFees,
-			TooExpensive => Self::TooExpensive,
-			Trap(i) => Self::Trap(i),
-			_ => return Err(()),
-		})
-	}
-}
-
-impl From<SendError> for Error {
-	fn from(e: SendError) -> Self {
-		match e {
-			SendError::NotApplicable(..) | SendError::Unroutable => Error::Unroutable,
-			SendError::Transport(s) => Error::Transport(s),
-			SendError::DestinationUnsupported => Error::DestinationUnsupported,
-			SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize,
-		}
-	}
-}
-
-pub type Result = result::Result<(), Error>;
-
-/// Outcome of an XCM execution.
-#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum Outcome {
-	/// Execution completed successfully; given weight was used.
-	Complete(Weight),
-	/// Execution started, but did not complete successfully due to the given error; given weight
-	/// was used.
-	Incomplete(Weight, Error),
-	/// Execution did not start due to the given error.
-	Error(Error),
-}
-
-impl Outcome {
-	pub fn ensure_complete(self) -> Result {
-		match self {
-			Outcome::Complete(_) => Ok(()),
-			Outcome::Incomplete(_, e) => Err(e),
-			Outcome::Error(e) => Err(e),
-		}
-	}
-	pub fn ensure_execution(self) -> result::Result<Weight, Error> {
-		match self {
-			Outcome::Complete(w) => Ok(w),
-			Outcome::Incomplete(w, _) => Ok(w),
-			Outcome::Error(e) => Err(e),
-		}
-	}
-	/// How much weight was used by the XCM execution attempt.
-	pub fn weight_used(&self) -> Weight {
-		match self {
-			Outcome::Complete(w) => *w,
-			Outcome::Incomplete(w, _) => *w,
-			Outcome::Error(_) => 0,
-		}
-	}
-}
-
-/// Type of XCM message executor.
-pub trait ExecuteXcm<RuntimeCall> {
-	/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The
-	/// weight limit is a basic hard-limit and the implementation may place further restrictions or
-	/// requirements on weight and other aspects.
-	fn execute_xcm(
-		origin: impl Into<MultiLocation>,
-		message: Xcm<RuntimeCall>,
-		weight_limit: Weight,
-	) -> Outcome {
-		let origin = origin.into();
-		log::debug!(
-			target: "xcm::execute_xcm",
-			"origin: {:?}, message: {:?}, weight_limit: {:?}",
-			origin,
-			message,
-			weight_limit,
-		);
-		Self::execute_xcm_in_credit(origin, message, weight_limit, 0)
-	}
-
-	/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight.
-	///
-	/// Some amount of `weight_credit` may be provided which, depending on the implementation, may
-	/// allow execution without associated payment.
-	fn execute_xcm_in_credit(
-		origin: impl Into<MultiLocation>,
-		message: Xcm<RuntimeCall>,
-		weight_limit: Weight,
-		weight_credit: Weight,
-	) -> Outcome;
-}
-
-impl<C> ExecuteXcm<C> for () {
-	fn execute_xcm_in_credit(
-		_origin: impl Into<MultiLocation>,
-		_message: Xcm<C>,
-		_weight_limit: Weight,
-		_weight_credit: Weight,
-	) -> Outcome {
-		Outcome::Error(Error::Unimplemented)
-	}
-}
-
-/// Error result value when attempting to send an XCM message.
-#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-pub enum SendError {
-	/// The message and destination combination was not recognized as being reachable.
-	///
-	/// This is not considered fatal: if there are alternative transport routes available, then
-	/// they may be attempted. For this reason, the destination and message are contained.
-	NotApplicable(MultiLocation, Xcm<()>),
-	/// Destination is routable, but there is some issue with the transport mechanism. This is
-	/// considered fatal.
-	/// A human-readable explanation of the specific issue is provided.
-	Transport(#[codec(skip)] &'static str),
-	/// Destination is known to be unroutable. This is considered fatal.
-	Unroutable,
-	/// The given message cannot be translated into a format that the destination can be expected
-	/// to interpret.
-	DestinationUnsupported,
-	/// Message could not be sent due to its size exceeding the maximum allowed by the transport
-	/// layer.
-	ExceedsMaxMessageSize,
-}
-
-/// Result value when attempting to send an XCM message.
-pub type SendResult = result::Result<(), SendError>;
-
-/// Utility for sending an XCM message.
-///
-/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each
-/// router might return `NotApplicable` to pass the execution to the next sender item. Note that
-/// each `NotApplicable` might alter the destination and the XCM message for to the next router.
-///
-///
-/// # Example
-/// ```rust
-/// # use staging_xcm::v2::prelude::*;
-/// # use codec::Encode;
-///
-/// /// A sender that only passes the message through and does nothing.
-/// struct Sender1;
-/// impl SendXcm for Sender1 {
-///     fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
-///         return Err(SendError::NotApplicable(destination.into(), message))
-///     }
-/// }
-///
-/// /// A sender that accepts a message that has two junctions, otherwise stops the routing.
-/// struct Sender2;
-/// impl SendXcm for Sender2 {
-///     fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
-///         let destination = destination.into();
-///         if destination.parents == 0 && destination.interior.len() == 2 {
-///             Ok(())
-///         } else {
-///             Err(SendError::Unroutable)
-///         }
-///     }
-/// }
-///
-/// /// A sender that accepts a message from a parent, passing through otherwise.
-/// struct Sender3;
-/// impl SendXcm for Sender3 {
-///     fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
-///         let destination = destination.into();
-///         match destination {
-///             MultiLocation { parents: 1, interior: Here } => Ok(()),
-///             _ => Err(SendError::NotApplicable(destination, message)),
-///         }
-///     }
-/// }
-///
-/// // A call to send via XCM. We don't really care about this.
-/// # fn main() {
-/// let call: Vec<u8> = ().encode();
-/// let message = Xcm(vec![Instruction::Transact {
-///     origin_type: OriginKind::Superuser,
-///     require_weight_at_most: 0,
-///     call: call.into(),
-/// }]);
-///
-/// assert!(
-///     // Sender2 will block this.
-///     <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
-///         .is_err()
-/// );
-///
-/// assert!(
-///     // Sender3 will catch this.
-///     <(Sender1, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
-///         .is_ok()
-/// );
-/// # }
-/// ```
-pub trait SendXcm {
-	/// Send an XCM `message` to a given `destination`.
-	///
-	/// If it is not a destination which can be reached with this type but possibly could by others,
-	/// then it *MUST* return `NotApplicable`. Any other error will cause the tuple implementation
-	/// to exit early without trying other type fields.
-	fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult;
-}
-
-#[impl_trait_for_tuples::impl_for_tuples(30)]
-impl SendXcm for Tuple {
-	fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
-		for_tuples!( #(
-			// we shadow `destination` and `message` in each expansion for the next one.
-			let (destination, message) = match Tuple::send_xcm(destination, message) {
-				Err(SendError::NotApplicable(d, m)) => (d, m),
-				o @ _ => return o,
-			};
-		)* );
-		Err(SendError::NotApplicable(destination.into(), message))
-	}
-}
diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs
index 24348bf2e67..24e9c16bf69 100644
--- a/polkadot/xcm/src/v3/junction.rs
+++ b/polkadot/xcm/src/v3/junction.rs
@@ -18,10 +18,6 @@
 
 use super::{Junctions, MultiLocation};
 use crate::{
-	v2::{
-		BodyId as OldBodyId, BodyPart as OldBodyPart, Junction as OldJunction,
-		NetworkId as OldNetworkId,
-	},
 	v4::{Junction as NewJunction, NetworkId as NewNetworkId},
 	VersionedLocation,
 };
@@ -80,30 +76,6 @@ pub enum NetworkId {
 	PolkadotBulletin,
 }
 
-impl From<OldNetworkId> for Option<NetworkId> {
-	fn from(old: OldNetworkId) -> Option<NetworkId> {
-		use OldNetworkId::*;
-		match old {
-			Any => None,
-			Named(_) => None,
-			Polkadot => Some(NetworkId::Polkadot),
-			Kusama => Some(NetworkId::Kusama),
-		}
-	}
-}
-
-impl TryFrom<OldNetworkId> for NetworkId {
-	type Error = ();
-	fn try_from(old: OldNetworkId) -> Result<Self, Self::Error> {
-		use OldNetworkId::*;
-		match old {
-			Any | Named(_) => Err(()),
-			Polkadot => Ok(NetworkId::Polkadot),
-			Kusama => Ok(NetworkId::Kusama),
-		}
-	}
-}
-
 impl From<NewNetworkId> for Option<NetworkId> {
 	fn from(new: NewNetworkId) -> Self {
 		Some(NetworkId::from(new))
@@ -175,32 +147,6 @@ pub enum BodyId {
 	Treasury,
 }
 
-impl TryFrom<OldBodyId> for BodyId {
-	type Error = ();
-	fn try_from(value: OldBodyId) -> Result<Self, ()> {
-		use OldBodyId::*;
-		Ok(match value {
-			Unit => Self::Unit,
-			Named(n) =>
-				if n.len() == 4 {
-					let mut r = [0u8; 4];
-					r.copy_from_slice(&n[..]);
-					Self::Moniker(r)
-				} else {
-					return Err(())
-				},
-			Index(n) => Self::Index(n),
-			Executive => Self::Executive,
-			Technical => Self::Technical,
-			Legislative => Self::Legislative,
-			Judicial => Self::Judicial,
-			Defense => Self::Defense,
-			Administration => Self::Administration,
-			Treasury => Self::Treasury,
-		})
-	}
-}
-
 /// A part of a pluralistic body.
 #[derive(
 	Copy,
@@ -262,20 +208,6 @@ impl BodyPart {
 	}
 }
 
-impl TryFrom<OldBodyPart> for BodyPart {
-	type Error = ();
-	fn try_from(value: OldBodyPart) -> Result<Self, ()> {
-		use OldBodyPart::*;
-		Ok(match value {
-			Voice => Self::Voice,
-			Members { count } => Self::Members { count },
-			Fraction { nom, denom } => Self::Fraction { nom, denom },
-			AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
-			MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
-		})
-	}
-}
-
 /// A single item in a path to describe the relative location of a consensus system.
 ///
 /// Each item assumes a pre-existing location as its context and is defined in terms of it.
@@ -409,36 +341,6 @@ impl From<u128> for Junction {
 	}
 }
 
-impl TryFrom<OldJunction> for Junction {
-	type Error = ();
-	fn try_from(value: OldJunction) -> Result<Self, ()> {
-		use OldJunction::*;
-		Ok(match value {
-			Parachain(id) => Self::Parachain(id),
-			AccountId32 { network, id } => Self::AccountId32 { network: network.into(), id },
-			AccountIndex64 { network, index } =>
-				Self::AccountIndex64 { network: network.into(), index },
-			AccountKey20 { network, key } => Self::AccountKey20 { network: network.into(), key },
-			PalletInstance(index) => Self::PalletInstance(index),
-			GeneralIndex(id) => Self::GeneralIndex(id),
-			GeneralKey(key) => match key.len() {
-				len @ 0..=32 => Self::GeneralKey {
-					length: len as u8,
-					data: {
-						let mut data = [0u8; 32];
-						data[..len].copy_from_slice(&key[..]);
-						data
-					},
-				},
-				_ => return Err(()),
-			},
-			OnlyChild => Self::OnlyChild,
-			Plurality { id, part } =>
-				Self::Plurality { id: id.try_into()?, part: part.try_into()? },
-		})
-	}
-}
-
 impl TryFrom<NewJunction> for Junction {
 	type Error = ();
 
@@ -496,30 +398,3 @@ impl Junction {
 		}
 	}
 }
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use alloc::vec;
-
-	#[test]
-	fn junction_round_trip_works() {
-		let j = Junction::GeneralKey { length: 32, data: [1u8; 32] };
-		let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
-		assert_eq!(j, k);
-
-		let j = OldJunction::GeneralKey(vec![1u8; 32].try_into().unwrap());
-		let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap();
-		assert_eq!(j, k);
-
-		let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap());
-		let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
-		assert_eq!(j, k);
-		let s: BoundedSlice<_, _> = (&k).try_into().unwrap();
-		assert_eq!(s, &[1u8, 2, 3, 4][..]);
-
-		let j = OldJunction::GeneralKey(vec![1u8, 2, 3, 4].try_into().unwrap());
-		let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap();
-		assert_eq!(j, k);
-	}
-}
diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs
index ff64c98e15b..b60209a440c 100644
--- a/polkadot/xcm/src/v3/mod.rs
+++ b/polkadot/xcm/src/v3/mod.rs
@@ -16,11 +16,6 @@
 
 //! Version 3 of the Cross-Consensus Message format data structures.
 
-#[allow(deprecated)]
-use super::v2::{
-	Instruction as OldInstruction, OriginKind as OldOriginKind, Response as OldResponse,
-	WeightLimit as OldWeightLimit, Xcm as OldXcm,
-};
 use super::v4::{
 	Instruction as NewInstruction, PalletInfo as NewPalletInfo,
 	QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
@@ -56,43 +51,6 @@ pub use traits::{
 	SendError, SendResult, SendXcm, Weight, XcmHash,
 };
 
-/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
-#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
-#[scale_info(replace_segment("staging_xcm", "xcm"))]
-#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
-pub enum OriginKind {
-	/// Origin should just be the native dispatch origin representation for the sender in the
-	/// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
-	/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
-	/// primary/native dispatch origin form.
-	Native,
-
-	/// Origin should just be the standard account-based origin with the sovereign account of
-	/// the sender. For Cumulus/Frame chains, this is the `Signed` origin.
-	SovereignAccount,
-
-	/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
-	/// This will not usually be an available option.
-	Superuser,
-
-	/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
-	/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
-	/// the `pallet_xcm::Origin::Xcm` type.
-	Xcm,
-}
-
-impl From<OldOriginKind> for OriginKind {
-	fn from(old: OldOriginKind) -> Self {
-		use OldOriginKind::*;
-		match old {
-			Native => Self::Native,
-			SovereignAccount => Self::SovereignAccount,
-			Superuser => Self::Superuser,
-			Xcm => Self::Xcm,
-		}
-	}
-}
-
 /// This module's XCM version.
 pub const VERSION: super::Version = 3;
 
@@ -456,14 +414,29 @@ impl From<WeightLimit> for Option<Weight> {
 	}
 }
 
-impl From<OldWeightLimit> for WeightLimit {
-	fn from(x: OldWeightLimit) -> Self {
-		use OldWeightLimit::*;
-		match x {
-			Limited(w) => Self::Limited(Weight::from_parts(w, DEFAULT_PROOF_SIZE)),
-			Unlimited => Self::Unlimited,
-		}
-	}
+/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
+#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
+#[scale_info(replace_segment("staging_xcm", "xcm"))]
+#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
+pub enum OriginKind {
+	/// Origin should just be the native dispatch origin representation for the sender in the
+	/// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
+	/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
+	/// primary/native dispatch origin form.
+	Native,
+
+	/// Origin should just be the standard account-based origin with the sovereign account of
+	/// the sender. For Cumulus/Frame chains, this is the `Signed` origin.
+	SovereignAccount,
+
+	/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
+	/// This will not usually be an available option.
+	Superuser,
+
+	/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
+	/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
+	/// the `pallet_xcm::Origin::Xcm` type.
+	Xcm,
 }
 
 /// Contextual data pertaining to a specific list of XCM instructions.
@@ -819,6 +792,7 @@ pub enum Instruction<Call> {
 	/// Kind: *Command*
 	///
 	/// Errors:
+	#[builder(pays_fees)]
 	BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
 
 	/// Refund any surplus weight previously bought with `BuyExecution`.
@@ -1327,31 +1301,6 @@ pub mod opaque {
 	pub type Instruction = super::Instruction<()>;
 }
 
-// Convert from a v2 response to a v3 response.
-impl TryFrom<OldResponse> for Response {
-	type Error = ();
-	fn try_from(old_response: OldResponse) -> result::Result<Self, ()> {
-		match old_response {
-			OldResponse::Assets(assets) => Ok(Self::Assets(assets.try_into()?)),
-			OldResponse::Version(version) => Ok(Self::Version(version)),
-			OldResponse::ExecutionResult(error) => Ok(Self::ExecutionResult(match error {
-				Some((i, e)) => Some((i, e.try_into()?)),
-				None => None,
-			})),
-			OldResponse::Null => Ok(Self::Null),
-		}
-	}
-}
-
-// Convert from a v2 XCM to a v3 XCM.
-#[allow(deprecated)]
-impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
-	type Error = ();
-	fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, ()> {
-		Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
-	}
-}
-
 // Convert from a v4 XCM to a v3 XCM.
 impl<Call> TryFrom<NewXcm<Call>> for Xcm<Call> {
 	type Error = ();
@@ -1501,109 +1450,6 @@ impl<Call> TryFrom<NewInstruction<Call>> for Instruction<Call> {
 	}
 }
 
-/// Default value for the proof size weight component when converting from V2. Set at 64 KB.
-/// NOTE: Make sure this is removed after we properly account for PoV weights.
-const DEFAULT_PROOF_SIZE: u64 = 64 * 1024;
-
-// Convert from a v2 instruction to a v3 instruction.
-impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
-	type Error = ();
-	fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, ()> {
-		use OldInstruction::*;
-		Ok(match old_instruction {
-			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
-			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
-			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
-			QueryResponse { query_id, response, max_weight } => Self::QueryResponse {
-				query_id,
-				response: response.try_into()?,
-				max_weight: Weight::from_parts(max_weight, DEFAULT_PROOF_SIZE),
-				querier: None,
-			},
-			TransferAsset { assets, beneficiary } => Self::TransferAsset {
-				assets: assets.try_into()?,
-				beneficiary: beneficiary.try_into()?,
-			},
-			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
-				assets: assets.try_into()?,
-				dest: dest.try_into()?,
-				xcm: xcm.try_into()?,
-			},
-			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
-				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
-			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
-			HrmpChannelClosing { initiator, sender, recipient } =>
-				Self::HrmpChannelClosing { initiator, sender, recipient },
-			Transact { origin_type, require_weight_at_most, call } => Self::Transact {
-				origin_kind: origin_type.into(),
-				require_weight_at_most: Weight::from_parts(
-					require_weight_at_most,
-					DEFAULT_PROOF_SIZE,
-				),
-				call: call.into(),
-			},
-			ReportError { query_id, dest, max_response_weight } => {
-				let response_info = QueryResponseInfo {
-					destination: dest.try_into()?,
-					query_id,
-					max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
-				};
-				Self::ReportError(response_info)
-			},
-			DepositAsset { assets, max_assets, beneficiary } => Self::DepositAsset {
-				assets: (assets, max_assets).try_into()?,
-				beneficiary: beneficiary.try_into()?,
-			},
-			DepositReserveAsset { assets, max_assets, dest, xcm } => {
-				let assets = (assets, max_assets).try_into()?;
-				Self::DepositReserveAsset { assets, dest: dest.try_into()?, xcm: xcm.try_into()? }
-			},
-			ExchangeAsset { give, receive } => {
-				let give = give.try_into()?;
-				let want = receive.try_into()?;
-				Self::ExchangeAsset { give, want, maximal: true }
-			},
-			InitiateReserveWithdraw { assets, reserve, xcm } => Self::InitiateReserveWithdraw {
-				assets: assets.try_into()?,
-				reserve: reserve.try_into()?,
-				xcm: xcm.try_into()?,
-			},
-			InitiateTeleport { assets, dest, xcm } => Self::InitiateTeleport {
-				assets: assets.try_into()?,
-				dest: dest.try_into()?,
-				xcm: xcm.try_into()?,
-			},
-			QueryHolding { query_id, dest, assets, max_response_weight } => {
-				let response_info = QueryResponseInfo {
-					destination: dest.try_into()?,
-					query_id,
-					max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
-				};
-				Self::ReportHolding { response_info, assets: assets.try_into()? }
-			},
-			BuyExecution { fees, weight_limit } =>
-				Self::BuyExecution { fees: fees.try_into()?, weight_limit: weight_limit.into() },
-			ClearOrigin => Self::ClearOrigin,
-			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
-			RefundSurplus => Self::RefundSurplus,
-			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
-			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
-			ClearError => Self::ClearError,
-			ClaimAsset { assets, ticket } => {
-				let assets = assets.try_into()?;
-				let ticket = ticket.try_into()?;
-				Self::ClaimAsset { assets, ticket }
-			},
-			Trap(code) => Self::Trap(code),
-			SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
-				query_id,
-				max_response_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE),
-			},
-			UnsubscribeVersion => Self::UnsubscribeVersion,
-		})
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	use super::{prelude::*, *};
diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs
index 56b46b1d921..e8bd3e167f6 100644
--- a/polkadot/xcm/src/v3/multiasset.rs
+++ b/polkadot/xcm/src/v3/multiasset.rs
@@ -27,18 +27,10 @@
 //!   filtering an XCM holding account.
 
 use super::{InteriorMultiLocation, MultiLocation};
-use crate::{
-	v2::{
-		AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
-		MultiAsset as OldMultiAsset, MultiAssetFilter as OldMultiAssetFilter,
-		MultiAssets as OldMultiAssets, WildFungibility as OldWildFungibility,
-		WildMultiAsset as OldWildMultiAsset,
-	},
-	v4::{
-		Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId,
-		AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility,
-		WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility,
-	},
+use crate::v4::{
+	Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId,
+	AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility,
+	WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility,
 };
 use alloc::{vec, vec::Vec};
 use bounded_collections::{BoundedVec, ConstU32};
@@ -85,22 +77,6 @@ pub enum AssetInstance {
 	Array32([u8; 32]),
 }
 
-impl TryFrom<OldAssetInstance> for AssetInstance {
-	type Error = ();
-	fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
-		use OldAssetInstance::*;
-		Ok(match value {
-			Undefined => Self::Undefined,
-			Index(n) => Self::Index(n),
-			Array4(n) => Self::Array4(n),
-			Array8(n) => Self::Array8(n),
-			Array16(n) => Self::Array16(n),
-			Array32(n) => Self::Array32(n),
-			Blob(_) => return Err(()),
-		})
-	}
-}
-
 impl TryFrom<NewAssetInstance> for AssetInstance {
 	type Error = ();
 	fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
@@ -340,17 +316,6 @@ impl<T: Into<AssetInstance>> From<T> for Fungibility {
 	}
 }
 
-impl TryFrom<OldFungibility> for Fungibility {
-	type Error = ();
-	fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
-		use OldFungibility::*;
-		Ok(match value {
-			Fungible(n) => Self::Fungible(n),
-			NonFungible(i) => Self::NonFungible(i.try_into()?),
-		})
-	}
-}
-
 impl TryFrom<NewFungibility> for Fungibility {
 	type Error = ();
 	fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
@@ -387,17 +352,6 @@ pub enum WildFungibility {
 	NonFungible,
 }
 
-impl TryFrom<OldWildFungibility> for WildFungibility {
-	type Error = ();
-	fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
-		use OldWildFungibility::*;
-		Ok(match value {
-			Fungible => Self::Fungible,
-			NonFungible => Self::NonFungible,
-		})
-	}
-}
-
 impl TryFrom<NewWildFungibility> for WildFungibility {
 	type Error = ();
 	fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
@@ -447,22 +401,6 @@ impl From<[u8; 32]> for AssetId {
 	}
 }
 
-impl TryFrom<OldAssetId> for AssetId {
-	type Error = ();
-	fn try_from(old: OldAssetId) -> Result<Self, ()> {
-		use OldAssetId::*;
-		Ok(match old {
-			Concrete(l) => Self::Concrete(l.try_into()?),
-			Abstract(v) if v.len() <= 32 => {
-				let mut r = [0u8; 32];
-				r[..v.len()].copy_from_slice(&v[..]);
-				Self::Abstract(r)
-			},
-			_ => return Err(()),
-		})
-	}
-}
-
 impl TryFrom<NewAssetId> for AssetId {
 	type Error = ();
 	fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
@@ -601,13 +539,6 @@ impl MultiAsset {
 	}
 }
 
-impl TryFrom<OldMultiAsset> for MultiAsset {
-	type Error = ();
-	fn try_from(old: OldMultiAsset) -> Result<Self, ()> {
-		Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
-	}
-}
-
 impl TryFrom<NewMultiAsset> for MultiAsset {
 	type Error = ();
 	fn try_from(new: NewMultiAsset) -> Result<Self, Self::Error> {
@@ -657,18 +588,6 @@ impl Decode for MultiAssets {
 	}
 }
 
-impl TryFrom<OldMultiAssets> for MultiAssets {
-	type Error = ();
-	fn try_from(old: OldMultiAssets) -> Result<Self, ()> {
-		let v = old
-			.drain()
-			.into_iter()
-			.map(MultiAsset::try_from)
-			.collect::<Result<Vec<_>, ()>>()?;
-		Ok(MultiAssets(v))
-	}
-}
-
 impl TryFrom<NewMultiAssets> for MultiAssets {
 	type Error = ();
 	fn try_from(new: NewMultiAssets) -> Result<Self, Self::Error> {
@@ -882,17 +801,6 @@ pub enum WildMultiAsset {
 	},
 }
 
-impl TryFrom<OldWildMultiAsset> for WildMultiAsset {
-	type Error = ();
-	fn try_from(old: OldWildMultiAsset) -> Result<WildMultiAsset, ()> {
-		use OldWildMultiAsset::*;
-		Ok(match old {
-			AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
-			All => Self::All,
-		})
-	}
-}
-
 impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
 	type Error = ();
 	fn try_from(new: NewWildMultiAsset) -> Result<Self, ()> {
@@ -907,19 +815,6 @@ impl TryFrom<NewWildMultiAsset> for WildMultiAsset {
 	}
 }
 
-impl TryFrom<(OldWildMultiAsset, u32)> for WildMultiAsset {
-	type Error = ();
-	fn try_from(old: (OldWildMultiAsset, u32)) -> Result<WildMultiAsset, ()> {
-		use OldWildMultiAsset::*;
-		let count = old.1;
-		Ok(match old.0 {
-			AllOf { id, fun } =>
-				Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
-			All => Self::AllCounted(count),
-		})
-	}
-}
-
 impl WildMultiAsset {
 	/// Returns true if `self` is a super-set of the given `inner` asset.
 	pub fn contains(&self, inner: &MultiAsset) -> bool {
@@ -1079,16 +974,6 @@ impl MultiAssetFilter {
 	}
 }
 
-impl TryFrom<OldMultiAssetFilter> for MultiAssetFilter {
-	type Error = ();
-	fn try_from(old: OldMultiAssetFilter) -> Result<MultiAssetFilter, ()> {
-		Ok(match old {
-			OldMultiAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
-			OldMultiAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
-		})
-	}
-}
-
 impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
 	type Error = ();
 	fn try_from(new: NewMultiAssetFilter) -> Result<MultiAssetFilter, Self::Error> {
@@ -1100,19 +985,6 @@ impl TryFrom<NewMultiAssetFilter> for MultiAssetFilter {
 	}
 }
 
-impl TryFrom<(OldMultiAssetFilter, u32)> for MultiAssetFilter {
-	type Error = ();
-	fn try_from(old: (OldMultiAssetFilter, u32)) -> Result<MultiAssetFilter, ()> {
-		let count = old.1;
-		Ok(match old.0 {
-			OldMultiAssetFilter::Definite(x) if count >= x.len() as u32 =>
-				Self::Definite(x.try_into()?),
-			OldMultiAssetFilter::Wild(x) => Self::Wild((x, count).try_into()?),
-			_ => return Err(()),
-		})
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	use super::super::prelude::*;
diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs
index e51981204d9..8f18312046f 100644
--- a/polkadot/xcm/src/v3/multilocation.rs
+++ b/polkadot/xcm/src/v3/multilocation.rs
@@ -17,9 +17,7 @@
 //! XCM `MultiLocation` datatype.
 
 use super::{Junction, Junctions};
-use crate::{
-	v2::MultiLocation as OldMultiLocation, v4::Location as NewMultiLocation, VersionedLocation,
-};
+use crate::{v4::Location as NewMultiLocation, VersionedLocation};
 use codec::{Decode, Encode, MaxEncodedLen};
 use core::result;
 use scale_info::TypeInfo;
@@ -464,13 +462,6 @@ impl MultiLocation {
 	}
 }
 
-impl TryFrom<OldMultiLocation> for MultiLocation {
-	type Error = ();
-	fn try_from(x: OldMultiLocation) -> result::Result<Self, ()> {
-		Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
-	}
-}
-
 impl TryFrom<NewMultiLocation> for Option<MultiLocation> {
 	type Error = ();
 	fn try_from(new: NewMultiLocation) -> result::Result<Self, Self::Error> {
@@ -759,37 +750,4 @@ mod tests {
 		let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42)));
 		assert_eq!(para_to_remote_para.chain_location(), expected);
 	}
-
-	#[test]
-	fn conversion_from_other_types_works() {
-		use crate::v2;
-
-		fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
-
-		takes_multilocation(Parent);
-		takes_multilocation(Here);
-		takes_multilocation(X1(Parachain(42)));
-		takes_multilocation((Ancestor(255), PalletInstance(8)));
-		takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
-		takes_multilocation((Ancestor(2), Here));
-		takes_multilocation(AncestorThen(
-			3,
-			X2(Parachain(43), AccountIndex64 { network: None, index: 155 }),
-		));
-		takes_multilocation((Parent, AccountId32 { network: None, id: [0; 32] }));
-		takes_multilocation((Parent, Here));
-		takes_multilocation(ParentThen(X1(Parachain(75))));
-		takes_multilocation([Parachain(100), PalletInstance(3)]);
-
-		assert_eq!(
-			v2::MultiLocation::from(v2::Junctions::Here).try_into(),
-			Ok(MultiLocation::here())
-		);
-		assert_eq!(v2::MultiLocation::from(v2::Parent).try_into(), Ok(MultiLocation::parent()));
-		assert_eq!(
-			v2::MultiLocation::from((v2::Parent, v2::Parent, v2::Junction::GeneralIndex(42u128),))
-				.try_into(),
-			Ok(MultiLocation { parents: 2, interior: X1(GeneralIndex(42u128)) }),
-		);
-	}
 }
diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs
index 34c46453b9a..1c862070892 100644
--- a/polkadot/xcm/src/v3/traits.rs
+++ b/polkadot/xcm/src/v3/traits.rs
@@ -16,20 +16,19 @@
 
 //! Cross-Consensus Message format data structures.
 
-use crate::v2::Error as OldError;
-use codec::{Decode, Encode, MaxEncodedLen};
+use crate::v5::Error as NewError;
 use core::result;
 use scale_info::TypeInfo;
 
 pub use sp_weights::Weight;
 
-use super::*;
-
 // A simple trait to get the weight of some object.
 pub trait GetWeight<W> {
 	fn weight(&self) -> sp_weights::Weight;
 }
 
+use super::*;
+
 /// Error codes used in XCM. The first errors codes have explicit indices and are part of the XCM
 /// format. Those trailing are merely part of the XCM implementation; there is no expectation that
 /// they will retain the same index over time.
@@ -166,25 +165,17 @@ pub enum Error {
 	ExceedsStackLimit,
 }
 
-impl MaxEncodedLen for Error {
-	fn max_encoded_len() -> usize {
-		// TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields
-		// marked `codec(skip)`. We can hard-code it with the right answer for now.
-		1
-	}
-}
-
-impl TryFrom<OldError> for Error {
+impl TryFrom<NewError> for Error {
 	type Error = ();
-	fn try_from(old_error: OldError) -> result::Result<Error, ()> {
-		use OldError::*;
-		Ok(match old_error {
+	fn try_from(new_error: NewError) -> result::Result<Error, ()> {
+		use NewError::*;
+		Ok(match new_error {
 			Overflow => Self::Overflow,
 			Unimplemented => Self::Unimplemented,
 			UntrustedReserveLocation => Self::UntrustedReserveLocation,
 			UntrustedTeleportLocation => Self::UntrustedTeleportLocation,
-			MultiLocationFull => Self::LocationFull,
-			MultiLocationNotInvertible => Self::LocationNotInvertible,
+			LocationFull => Self::LocationFull,
+			LocationNotInvertible => Self::LocationNotInvertible,
 			BadOrigin => Self::BadOrigin,
 			InvalidLocation => Self::InvalidLocation,
 			AssetNotFound => Self::AssetNotFound,
@@ -201,11 +192,32 @@ impl TryFrom<OldError> for Error {
 			NotHoldingFees => Self::NotHoldingFees,
 			TooExpensive => Self::TooExpensive,
 			Trap(i) => Self::Trap(i),
+			ExpectationFalse => Self::ExpectationFalse,
+			PalletNotFound => Self::PalletNotFound,
+			NameMismatch => Self::NameMismatch,
+			VersionIncompatible => Self::VersionIncompatible,
+			HoldingWouldOverflow => Self::HoldingWouldOverflow,
+			ExportError => Self::ExportError,
+			ReanchorFailed => Self::ReanchorFailed,
+			NoDeal => Self::NoDeal,
+			FeesNotMet => Self::FeesNotMet,
+			LockError => Self::LockError,
+			NoPermission => Self::NoPermission,
+			Unanchored => Self::Unanchored,
+			NotDepositable => Self::NotDepositable,
 			_ => return Err(()),
 		})
 	}
 }
 
+impl MaxEncodedLen for Error {
+	fn max_encoded_len() -> usize {
+		// TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields
+		// marked `codec(skip)`. We can hard-code it with the right answer for now.
+		1
+	}
+}
+
 impl From<SendError> for Error {
 	fn from(e: SendError) -> Self {
 		match e {
diff --git a/polkadot/xcm/src/v4/asset.rs b/polkadot/xcm/src/v4/asset.rs
index 41f1f82f828..d7a9297d693 100644
--- a/polkadot/xcm/src/v4/asset.rs
+++ b/polkadot/xcm/src/v4/asset.rs
@@ -27,10 +27,17 @@
 //!   holding account.
 
 use super::{InteriorLocation, Location, Reanchorable};
-use crate::v3::{
-	AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
-	MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
-	WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
+use crate::{
+	v3::{
+		AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility,
+		MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets,
+		WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset,
+	},
+	v5::{
+		Asset as NewAsset, AssetFilter as NewAssetFilter, AssetId as NewAssetId,
+		AssetInstance as NewAssetInstance, Assets as NewAssets, Fungibility as NewFungibility,
+		WildAsset as NewWildAsset, WildFungibility as NewWildFungibility,
+	},
 };
 use alloc::{vec, vec::Vec};
 use bounded_collections::{BoundedVec, ConstU32};
@@ -90,6 +97,21 @@ impl TryFrom<OldAssetInstance> for AssetInstance {
 	}
 }
 
+impl TryFrom<NewAssetInstance> for AssetInstance {
+	type Error = ();
+	fn try_from(value: NewAssetInstance) -> Result<Self, Self::Error> {
+		use NewAssetInstance::*;
+		Ok(match value {
+			Undefined => Self::Undefined,
+			Index(n) => Self::Index(n),
+			Array4(n) => Self::Array4(n),
+			Array8(n) => Self::Array8(n),
+			Array16(n) => Self::Array16(n),
+			Array32(n) => Self::Array32(n),
+		})
+	}
+}
+
 impl From<()> for AssetInstance {
 	fn from(_: ()) -> Self {
 		Self::Undefined
@@ -244,6 +266,17 @@ impl TryFrom<AssetInstance> for u128 {
 	}
 }
 
+impl TryFrom<NewFungibility> for Fungibility {
+	type Error = ();
+	fn try_from(value: NewFungibility) -> Result<Self, Self::Error> {
+		use NewFungibility::*;
+		Ok(match value {
+			Fungible(n) => Self::Fungible(n),
+			NonFungible(i) => Self::NonFungible(i.try_into()?),
+		})
+	}
+}
+
 /// Classification of whether an asset is fungible or not, along with a mandatory amount or
 /// instance.
 #[derive(
@@ -357,6 +390,17 @@ impl TryFrom<OldWildFungibility> for WildFungibility {
 	}
 }
 
+impl TryFrom<NewWildFungibility> for WildFungibility {
+	type Error = ();
+	fn try_from(value: NewWildFungibility) -> Result<Self, Self::Error> {
+		use NewWildFungibility::*;
+		Ok(match value {
+			Fungible => Self::Fungible,
+			NonFungible => Self::NonFungible,
+		})
+	}
+}
+
 /// Location to identify an asset.
 #[derive(
 	Clone,
@@ -391,6 +435,13 @@ impl TryFrom<OldAssetId> for AssetId {
 	}
 }
 
+impl TryFrom<NewAssetId> for AssetId {
+	type Error = ();
+	fn try_from(new: NewAssetId) -> Result<Self, Self::Error> {
+		Ok(Self(new.0.try_into()?))
+	}
+}
+
 impl AssetId {
 	/// Prepend a `Location` to an asset id, giving it a new root location.
 	pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
@@ -526,6 +577,13 @@ impl TryFrom<OldAsset> for Asset {
 	}
 }
 
+impl TryFrom<NewAsset> for Asset {
+	type Error = ();
+	fn try_from(new: NewAsset) -> Result<Self, Self::Error> {
+		Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? })
+	}
+}
+
 /// A `Vec` of `Asset`s.
 ///
 /// There are a number of invariants which the construction and mutation functions must ensure are
@@ -579,6 +637,18 @@ impl TryFrom<OldAssets> for Assets {
 	}
 }
 
+impl TryFrom<NewAssets> for Assets {
+	type Error = ();
+	fn try_from(new: NewAssets) -> Result<Self, Self::Error> {
+		let v = new
+			.into_inner()
+			.into_iter()
+			.map(Asset::try_from)
+			.collect::<Result<Vec<_>, ()>>()?;
+		Ok(Assets(v))
+	}
+}
+
 impl From<Vec<Asset>> for Assets {
 	fn from(mut assets: Vec<Asset>) -> Self {
 		let mut res = Vec::with_capacity(assets.len());
@@ -795,6 +865,20 @@ impl TryFrom<OldWildAsset> for WildAsset {
 	}
 }
 
+impl TryFrom<NewWildAsset> for WildAsset {
+	type Error = ();
+	fn try_from(new: NewWildAsset) -> Result<Self, ()> {
+		use NewWildAsset::*;
+		Ok(match new {
+			AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
+			AllOfCounted { id, fun, count } =>
+				Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
+			All => Self::All,
+			AllCounted(count) => Self::AllCounted(count),
+		})
+	}
+}
+
 impl WildAsset {
 	/// Returns true if `self` is a super-set of the given `inner` asset.
 	pub fn contains(&self, inner: &Asset) -> bool {
@@ -944,6 +1028,17 @@ impl AssetFilter {
 	}
 }
 
+impl TryFrom<NewAssetFilter> for AssetFilter {
+	type Error = ();
+	fn try_from(new: NewAssetFilter) -> Result<AssetFilter, Self::Error> {
+		use NewAssetFilter::*;
+		Ok(match new {
+			Definite(x) => Self::Definite(x.try_into()?),
+			Wild(x) => Self::Wild(x.try_into()?),
+		})
+	}
+}
+
 impl TryFrom<OldAssetFilter> for AssetFilter {
 	type Error = ();
 	fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
diff --git a/polkadot/xcm/src/v4/junction.rs b/polkadot/xcm/src/v4/junction.rs
index 36fb616d2dc..c6e83214328 100644
--- a/polkadot/xcm/src/v4/junction.rs
+++ b/polkadot/xcm/src/v4/junction.rs
@@ -20,6 +20,7 @@ use super::Location;
 pub use crate::v3::{BodyId, BodyPart};
 use crate::{
 	v3::{Junction as OldJunction, NetworkId as OldNetworkId},
+	v5::{Junction as NewJunction, NetworkId as NewNetworkId},
 	VersionedLocation,
 };
 use bounded_collections::{BoundedSlice, BoundedVec, ConstU32};
@@ -72,7 +73,6 @@ pub enum Junction {
 	/// An instanced, indexed pallet that forms a constituent part of the context.
 	///
 	/// Generally used when the context is a Frame-based chain.
-	// TODO XCMv4 inner should be `Compact<u32>`.
 	PalletInstance(u8),
 	/// A non-descript index within the context location.
 	///
@@ -103,6 +103,28 @@ pub enum Junction {
 	GlobalConsensus(NetworkId),
 }
 
+impl From<NewNetworkId> for Option<NetworkId> {
+	fn from(new: NewNetworkId) -> Self {
+		Some(NetworkId::from(new))
+	}
+}
+
+impl From<NewNetworkId> for NetworkId {
+	fn from(new: NewNetworkId) -> Self {
+		use NewNetworkId::*;
+		match new {
+			ByGenesis(hash) => Self::ByGenesis(hash),
+			ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
+			Polkadot => Self::Polkadot,
+			Kusama => Self::Kusama,
+			Ethereum { chain_id } => Self::Ethereum { chain_id },
+			BitcoinCore => Self::BitcoinCore,
+			BitcoinCash => Self::BitcoinCash,
+			PolkadotBulletin => Self::PolkadotBulletin,
+		}
+	}
+}
+
 /// A global identifier of a data structure existing within consensus.
 ///
 /// Maintenance note: Networks with global consensus and which are practically bridgeable within the
@@ -253,6 +275,29 @@ impl TryFrom<OldJunction> for Junction {
 	}
 }
 
+impl TryFrom<NewJunction> for Junction {
+	type Error = ();
+
+	fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
+		use NewJunction::*;
+		Ok(match value {
+			Parachain(id) => Self::Parachain(id),
+			AccountId32 { network: maybe_network, id } =>
+				Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
+			AccountIndex64 { network: maybe_network, index } =>
+				Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
+			AccountKey20 { network: maybe_network, key } =>
+				Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
+			PalletInstance(index) => Self::PalletInstance(index),
+			GeneralIndex(id) => Self::GeneralIndex(id),
+			GeneralKey { length, data } => Self::GeneralKey { length, data },
+			OnlyChild => Self::OnlyChild,
+			Plurality { id, part } => Self::Plurality { id, part },
+			GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
+		})
+	}
+}
+
 impl Junction {
 	/// Convert `self` into a `Location` containing 0 parents.
 	///
diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs
index f2c302495c7..3a44b0696be 100644
--- a/polkadot/xcm/src/v4/location.rs
+++ b/polkadot/xcm/src/v4/location.rs
@@ -17,7 +17,7 @@
 //! XCM `Location` datatype.
 
 use super::{traits::Reanchorable, Junction, Junctions};
-use crate::{v3::MultiLocation as OldLocation, VersionedLocation};
+use crate::{v3::MultiLocation as OldLocation, v5::Location as NewLocation, VersionedLocation};
 use codec::{Decode, Encode, MaxEncodedLen};
 use core::result;
 use scale_info::TypeInfo;
@@ -489,6 +489,20 @@ impl TryFrom<OldLocation> for Location {
 	}
 }
 
+impl TryFrom<NewLocation> for Option<Location> {
+	type Error = ();
+	fn try_from(new: NewLocation) -> result::Result<Self, Self::Error> {
+		Ok(Some(Location::try_from(new)?))
+	}
+}
+
+impl TryFrom<NewLocation> for Location {
+	type Error = ();
+	fn try_from(new: NewLocation) -> result::Result<Self, ()> {
+		Ok(Location { parents: new.parent_count(), interior: new.interior().clone().try_into()? })
+	}
+}
+
 /// A unit struct which can be converted into a `Location` of `parents` value 1.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct Parent;
diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs
index a2b12dcc54c..545b75a99ff 100644
--- a/polkadot/xcm/src/v4/mod.rs
+++ b/polkadot/xcm/src/v4/mod.rs
@@ -17,9 +17,15 @@
 //! Version 4 of the Cross-Consensus Message format data structures.
 
 pub use super::v3::GetWeight;
-use super::v3::{
-	Instruction as OldInstruction, PalletInfo as OldPalletInfo,
-	QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
+use super::{
+	v3::{
+		Instruction as OldInstruction, PalletInfo as OldPalletInfo,
+		QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
+	},
+	v5::{
+		Instruction as NewInstruction, PalletInfo as NewPalletInfo,
+		QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
+	},
 };
 use crate::DoubleEncoded;
 use alloc::{vec, vec::Vec};
@@ -30,6 +36,7 @@ use codec::{
 };
 use core::{fmt::Debug, result};
 use derivative::Derivative;
+use frame_support::dispatch::GetDispatchInfo;
 use scale_info::TypeInfo;
 
 mod asset;
@@ -50,7 +57,7 @@ pub use traits::{
 	SendError, SendResult, SendXcm, Weight, XcmHash,
 };
 // These parts of XCM v3 are unchanged in XCM v4, and are re-imported here.
-pub use super::v3::{MaybeErrorCode, OriginKind, WeightLimit};
+pub use super::v3::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit};
 
 /// This module's XCM version.
 pub const VERSION: super::Version = 4;
@@ -222,9 +229,6 @@ pub mod prelude {
 
 parameter_types! {
 	pub MaxPalletNameLen: u32 = 48;
-	/// Maximum size of the encoded error code coming from a `Dispatch` result, used for
-	/// `MaybeErrorCode`. This is not (yet) enforced, so it's just an indication of expectation.
-	pub MaxDispatchErrorLen: u32 = 128;
 	pub MaxPalletsInfo: u32 = 64;
 }
 
@@ -258,6 +262,22 @@ impl TryInto<OldPalletInfo> for PalletInfo {
 	}
 }
 
+impl TryInto<NewPalletInfo> for PalletInfo {
+	type Error = ();
+
+	fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
+		NewPalletInfo::new(
+			self.index,
+			self.name.into_inner(),
+			self.module_name.into_inner(),
+			self.major,
+			self.minor,
+			self.patch,
+		)
+		.map_err(|_| ())
+	}
+}
+
 impl PalletInfo {
 	pub fn new(
 		index: u32,
@@ -322,6 +342,36 @@ impl TryFrom<OldResponse> for Response {
 	}
 }
 
+impl TryFrom<NewResponse> for Response {
+	type Error = ();
+
+	fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
+		use NewResponse::*;
+		Ok(match new {
+			Null => Self::Null,
+			Assets(assets) => Self::Assets(assets.try_into()?),
+			ExecutionResult(result) => Self::ExecutionResult(
+				result
+					.map(|(num, new_error)| (num, new_error.try_into()))
+					.map(|(num, result)| result.map(|inner| (num, inner)))
+					.transpose()?,
+			),
+			Version(version) => Self::Version(version),
+			PalletsInfo(pallet_info) => {
+				let inner = pallet_info
+					.into_iter()
+					.map(TryInto::try_into)
+					.collect::<result::Result<Vec<_>, _>>()?;
+				Self::PalletsInfo(
+					BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
+				)
+			},
+			DispatchResult(maybe_error) =>
+				Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?),
+		})
+	}
+}
+
 /// Information regarding the composition of a query response.
 #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
 pub struct QueryResponseInfo {
@@ -334,6 +384,18 @@ pub struct QueryResponseInfo {
 	pub max_weight: Weight,
 }
 
+impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
+	type Error = ();
+
+	fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
+		Ok(Self {
+			destination: new.destination.try_into()?,
+			query_id: new.query_id,
+			max_weight: new.max_weight,
+		})
+	}
+}
+
 impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
 	type Error = ();
 
@@ -690,6 +752,7 @@ pub enum Instruction<Call> {
 	/// Kind: *Command*
 	///
 	/// Errors:
+	#[builder(pays_fees)]
 	BuyExecution { fees: Asset, weight_limit: WeightLimit },
 
 	/// Refund any surplus weight previously bought with `BuyExecution`.
@@ -1206,6 +1269,166 @@ impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
 	}
 }
 
+// Convert from a v5 XCM to a v4 XCM.
+impl<Call: Decode + GetDispatchInfo> TryFrom<NewXcm<Call>> for Xcm<Call> {
+	type Error = ();
+	fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
+		Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
+	}
+}
+
+// Convert from a v5 instruction to a v4 instruction.
+impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instruction<Call> {
+	type Error = ();
+	fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
+		use NewInstruction::*;
+		Ok(match new_instruction {
+			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
+			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
+			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
+			QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
+				Self::QueryResponse {
+					query_id,
+					querier: querier.try_into()?,
+					response: response.try_into()?,
+					max_weight,
+				},
+			QueryResponse { query_id, response, max_weight, querier: None } =>
+				Self::QueryResponse {
+					query_id,
+					querier: None,
+					response: response.try_into()?,
+					max_weight,
+				},
+			TransferAsset { assets, beneficiary } => Self::TransferAsset {
+				assets: assets.try_into()?,
+				beneficiary: beneficiary.try_into()?,
+			},
+			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
+				assets: assets.try_into()?,
+				dest: dest.try_into()?,
+				xcm: xcm.try_into()?,
+			},
+			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
+				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
+			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
+			HrmpChannelClosing { initiator, sender, recipient } =>
+				Self::HrmpChannelClosing { initiator, sender, recipient },
+			Transact { origin_kind, mut call } => {
+				let require_weight_at_most = call.take_decoded()?.get_dispatch_info().call_weight;
+				Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
+			},
+			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
+				query_id: response_info.query_id,
+				destination: response_info.destination.try_into().map_err(|_| ())?,
+				max_weight: response_info.max_weight,
+			}),
+			DepositAsset { assets, beneficiary } => {
+				let beneficiary = beneficiary.try_into()?;
+				let assets = assets.try_into()?;
+				Self::DepositAsset { assets, beneficiary }
+			},
+			DepositReserveAsset { assets, dest, xcm } => {
+				let dest = dest.try_into()?;
+				let xcm = xcm.try_into()?;
+				let assets = assets.try_into()?;
+				Self::DepositReserveAsset { assets, dest, xcm }
+			},
+			ExchangeAsset { give, want, maximal } => {
+				let give = give.try_into()?;
+				let want = want.try_into()?;
+				Self::ExchangeAsset { give, want, maximal }
+			},
+			InitiateReserveWithdraw { assets, reserve, xcm } => {
+				// No `max_assets` here, so if there's a connt, then we cannot translate.
+				let assets = assets.try_into()?;
+				let reserve = reserve.try_into()?;
+				let xcm = xcm.try_into()?;
+				Self::InitiateReserveWithdraw { assets, reserve, xcm }
+			},
+			InitiateTeleport { assets, dest, xcm } => {
+				// No `max_assets` here, so if there's a connt, then we cannot translate.
+				let assets = assets.try_into()?;
+				let dest = dest.try_into()?;
+				let xcm = xcm.try_into()?;
+				Self::InitiateTeleport { assets, dest, xcm }
+			},
+			ReportHolding { response_info, assets } => {
+				let response_info = QueryResponseInfo {
+					destination: response_info.destination.try_into().map_err(|_| ())?,
+					query_id: response_info.query_id,
+					max_weight: response_info.max_weight,
+				};
+				Self::ReportHolding { response_info, assets: assets.try_into()? }
+			},
+			BuyExecution { fees, weight_limit } => {
+				let fees = fees.try_into()?;
+				let weight_limit = weight_limit.into();
+				Self::BuyExecution { fees, weight_limit }
+			},
+			ClearOrigin => Self::ClearOrigin,
+			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
+			RefundSurplus => Self::RefundSurplus,
+			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
+			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
+			ClearError => Self::ClearError,
+			ClaimAsset { assets, ticket } => {
+				let assets = assets.try_into()?;
+				let ticket = ticket.try_into()?;
+				Self::ClaimAsset { assets, ticket }
+			},
+			Trap(code) => Self::Trap(code),
+			SubscribeVersion { query_id, max_response_weight } =>
+				Self::SubscribeVersion { query_id, max_response_weight },
+			UnsubscribeVersion => Self::UnsubscribeVersion,
+			BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
+			ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
+			ExpectOrigin(maybe_origin) =>
+				Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?),
+			ExpectError(maybe_error) => Self::ExpectError(
+				maybe_error
+					.map(|(num, new_error)| (num, new_error.try_into()))
+					.map(|(num, result)| result.map(|inner| (num, inner)))
+					.transpose()?,
+			),
+			ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
+			QueryPallet { module_name, response_info } =>
+				Self::QueryPallet { module_name, response_info: response_info.try_into()? },
+			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
+				Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
+			ReportTransactStatus(response_info) =>
+				Self::ReportTransactStatus(response_info.try_into()?),
+			ClearTransactStatus => Self::ClearTransactStatus,
+			UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
+			ExportMessage { network, destination, xcm } => Self::ExportMessage {
+				network: network.into(),
+				destination: destination.try_into()?,
+				xcm: xcm.try_into()?,
+			},
+			LockAsset { asset, unlocker } =>
+				Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? },
+			UnlockAsset { asset, target } =>
+				Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? },
+			NoteUnlockable { asset, owner } =>
+				Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? },
+			RequestUnlock { asset, locker } =>
+				Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? },
+			SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
+			SetTopic(topic) => Self::SetTopic(topic),
+			ClearTopic => Self::ClearTopic,
+			AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
+			UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
+				weight_limit,
+				check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
+			},
+			InitiateTransfer { .. } | PayFees { .. } | SetAssetClaimer { .. } => {
+				log::debug!(target: "xcm::v5tov4", "`{new_instruction:?}` not supported by v4");
+				return Err(());
+			},
+		})
+	}
+}
+
 // Convert from a v3 instruction to a v4 instruction
 impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
 	type Error = ();
diff --git a/polkadot/xcm/src/v5/asset.rs b/polkadot/xcm/src/v5/asset.rs
new file mode 100644
index 00000000000..d0d9a7cedff
--- /dev/null
+++ b/polkadot/xcm/src/v5/asset.rs
@@ -0,0 +1,1155 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Cross-Consensus Message format asset data structures.
+//!
+//! This encompasses four types for representing assets:
+//! - `Asset`: A description of a single asset, either an instance of a non-fungible or some amount
+//!   of a fungible.
+//! - `Assets`: A collection of `Asset`s. These are stored in a `Vec` and sorted with fungibles
+//!   first.
+//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific
+//!   kind.
+//! - `AssetFilter`: A combination of `Wild` and `Assets` designed for efficiently filtering an XCM
+//!   holding account.
+
+use super::{InteriorLocation, Location, Reanchorable};
+use crate::v4::{
+	Asset as OldAsset, AssetFilter as OldAssetFilter, AssetId as OldAssetId,
+	AssetInstance as OldAssetInstance, Assets as OldAssets, Fungibility as OldFungibility,
+	WildAsset as OldWildAsset, WildFungibility as OldWildFungibility,
+};
+use alloc::{vec, vec::Vec};
+use bounded_collections::{BoundedVec, ConstU32};
+use codec::{self as codec, Decode, Encode, MaxEncodedLen};
+use core::cmp::Ordering;
+use scale_info::TypeInfo;
+
+/// A general identifier for an instance of a non-fungible asset class.
+#[derive(
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Encode,
+	Decode,
+	Debug,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum AssetInstance {
+	/// Undefined - used if the non-fungible asset class has only one instance.
+	Undefined,
+
+	/// A compact index. Technically this could be greater than `u128`, but this implementation
+	/// supports only values up to `2**128 - 1`.
+	Index(#[codec(compact)] u128),
+
+	/// A 4-byte fixed-length datum.
+	Array4([u8; 4]),
+
+	/// An 8-byte fixed-length datum.
+	Array8([u8; 8]),
+
+	/// A 16-byte fixed-length datum.
+	Array16([u8; 16]),
+
+	/// A 32-byte fixed-length datum.
+	Array32([u8; 32]),
+}
+
+impl TryFrom<OldAssetInstance> for AssetInstance {
+	type Error = ();
+	fn try_from(value: OldAssetInstance) -> Result<Self, Self::Error> {
+		use OldAssetInstance::*;
+		Ok(match value {
+			Undefined => Self::Undefined,
+			Index(n) => Self::Index(n),
+			Array4(n) => Self::Array4(n),
+			Array8(n) => Self::Array8(n),
+			Array16(n) => Self::Array16(n),
+			Array32(n) => Self::Array32(n),
+		})
+	}
+}
+
+impl From<()> for AssetInstance {
+	fn from(_: ()) -> Self {
+		Self::Undefined
+	}
+}
+
+impl From<[u8; 4]> for AssetInstance {
+	fn from(x: [u8; 4]) -> Self {
+		Self::Array4(x)
+	}
+}
+
+impl From<[u8; 8]> for AssetInstance {
+	fn from(x: [u8; 8]) -> Self {
+		Self::Array8(x)
+	}
+}
+
+impl From<[u8; 16]> for AssetInstance {
+	fn from(x: [u8; 16]) -> Self {
+		Self::Array16(x)
+	}
+}
+
+impl From<[u8; 32]> for AssetInstance {
+	fn from(x: [u8; 32]) -> Self {
+		Self::Array32(x)
+	}
+}
+
+impl From<u8> for AssetInstance {
+	fn from(x: u8) -> Self {
+		Self::Index(x as u128)
+	}
+}
+
+impl From<u16> for AssetInstance {
+	fn from(x: u16) -> Self {
+		Self::Index(x as u128)
+	}
+}
+
+impl From<u32> for AssetInstance {
+	fn from(x: u32) -> Self {
+		Self::Index(x as u128)
+	}
+}
+
+impl From<u64> for AssetInstance {
+	fn from(x: u64) -> Self {
+		Self::Index(x as u128)
+	}
+}
+
+impl TryFrom<AssetInstance> for () {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Undefined => Ok(()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for [u8; 4] {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Array4(x) => Ok(x),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for [u8; 8] {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Array8(x) => Ok(x),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for [u8; 16] {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Array16(x) => Ok(x),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for [u8; 32] {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Array32(x) => Ok(x),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for u8 {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for u16 {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for u32 {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for u64 {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Index(x) => x.try_into().map_err(|_| ()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl TryFrom<AssetInstance> for u128 {
+	type Error = ();
+	fn try_from(x: AssetInstance) -> Result<Self, ()> {
+		match x {
+			AssetInstance::Index(x) => Ok(x),
+			_ => Err(()),
+		}
+	}
+}
+
+/// Classification of whether an asset is fungible or not, along with a mandatory amount or
+/// instance.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum Fungibility {
+	/// A fungible asset; we record a number of units, as a `u128` in the inner item.
+	Fungible(#[codec(compact)] u128),
+	/// A non-fungible asset. We record the instance identifier in the inner item. Only one asset
+	/// of each instance identifier may ever be in existence at once.
+	NonFungible(AssetInstance),
+}
+
+#[derive(Decode)]
+enum UncheckedFungibility {
+	Fungible(#[codec(compact)] u128),
+	NonFungible(AssetInstance),
+}
+
+impl Decode for Fungibility {
+	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
+		match UncheckedFungibility::decode(input)? {
+			UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)),
+			UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)),
+			UncheckedFungibility::Fungible(_) =>
+				Err("Fungible asset of zero amount is not allowed".into()),
+		}
+	}
+}
+
+impl Fungibility {
+	pub fn is_kind(&self, w: WildFungibility) -> bool {
+		use Fungibility::*;
+		use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible};
+		matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible))
+	}
+}
+
+impl From<i32> for Fungibility {
+	fn from(amount: i32) -> Fungibility {
+		debug_assert_ne!(amount, 0);
+		Fungibility::Fungible(amount as u128)
+	}
+}
+
+impl From<u128> for Fungibility {
+	fn from(amount: u128) -> Fungibility {
+		debug_assert_ne!(amount, 0);
+		Fungibility::Fungible(amount)
+	}
+}
+
+impl<T: Into<AssetInstance>> From<T> for Fungibility {
+	fn from(instance: T) -> Fungibility {
+		Fungibility::NonFungible(instance.into())
+	}
+}
+
+impl TryFrom<OldFungibility> for Fungibility {
+	type Error = ();
+	fn try_from(value: OldFungibility) -> Result<Self, Self::Error> {
+		use OldFungibility::*;
+		Ok(match value {
+			Fungible(n) => Self::Fungible(n),
+			NonFungible(i) => Self::NonFungible(i.try_into()?),
+		})
+	}
+}
+
+/// Classification of whether an asset is fungible or not.
+#[derive(
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum WildFungibility {
+	/// The asset is fungible.
+	Fungible,
+	/// The asset is not fungible.
+	NonFungible,
+}
+
+impl TryFrom<OldWildFungibility> for WildFungibility {
+	type Error = ();
+	fn try_from(value: OldWildFungibility) -> Result<Self, Self::Error> {
+		use OldWildFungibility::*;
+		Ok(match value {
+			Fungible => Self::Fungible,
+			NonFungible => Self::NonFungible,
+		})
+	}
+}
+
+/// Location to identify an asset.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub struct AssetId(pub Location);
+
+impl<T: Into<Location>> From<T> for AssetId {
+	fn from(x: T) -> Self {
+		Self(x.into())
+	}
+}
+
+impl TryFrom<OldAssetId> for AssetId {
+	type Error = ();
+	fn try_from(old: OldAssetId) -> Result<Self, ()> {
+		Ok(Self(old.0.try_into()?))
+	}
+}
+
+impl AssetId {
+	/// Prepend a `Location` to an asset id, giving it a new root location.
+	pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
+		self.0.prepend_with(prepend.clone()).map_err(|_| ())?;
+		Ok(())
+	}
+
+	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
+	/// `Asset` value.
+	pub fn into_asset(self, fun: Fungibility) -> Asset {
+		Asset { fun, id: self }
+	}
+
+	/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding
+	/// `WildAsset` wildcard (`AllOf`) value.
+	pub fn into_wild(self, fun: WildFungibility) -> WildAsset {
+		WildAsset::AllOf { fun, id: self }
+	}
+}
+
+impl Reanchorable for AssetId {
+	type Error = ();
+
+	/// Mutate the asset to represent the same value from the perspective of a new `target`
+	/// location. The local chain's location is provided in `context`.
+	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		self.0.reanchor(target, context)?;
+		Ok(())
+	}
+
+	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
+		match self.reanchor(target, context) {
+			Ok(()) => Ok(self),
+			Err(()) => Err(()),
+		}
+	}
+}
+
+/// Either an amount of a single fungible asset, or a single well-identified non-fungible asset.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub struct Asset {
+	/// The overall asset identity (aka *class*, in the case of a non-fungible).
+	pub id: AssetId,
+	/// The fungibility of the asset, which contains either the amount (in the case of a fungible
+	/// asset) or the *instance ID*, the secondary asset identifier.
+	pub fun: Fungibility,
+}
+
+impl PartialOrd for Asset {
+	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+		Some(self.cmp(other))
+	}
+}
+
+impl Ord for Asset {
+	fn cmp(&self, other: &Self) -> Ordering {
+		match (&self.fun, &other.fun) {
+			(Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less,
+			(Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater,
+			_ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)),
+		}
+	}
+}
+
+impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for Asset {
+	fn from((id, fun): (A, B)) -> Asset {
+		Asset { fun: fun.into(), id: id.into() }
+	}
+}
+
+impl Asset {
+	pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool {
+		use Fungibility::*;
+		matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id)
+	}
+
+	pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool {
+		use Fungibility::*;
+		matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id)
+	}
+
+	/// Prepend a `Location` to a concrete asset, giving it a new root location.
+	pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> {
+		self.id.prepend_with(prepend)
+	}
+
+	/// Returns true if `self` is a super-set of the given `inner` asset.
+	pub fn contains(&self, inner: &Asset) -> bool {
+		use Fungibility::*;
+		if self.id == inner.id {
+			match (&self.fun, &inner.fun) {
+				(Fungible(a), Fungible(i)) if a >= i => return true,
+				(NonFungible(a), NonFungible(i)) if a == i => return true,
+				_ => (),
+			}
+		}
+		false
+	}
+}
+
+impl Reanchorable for Asset {
+	type Error = ();
+
+	/// Mutate the location of the asset identifier if concrete, giving it the same location
+	/// relative to a `target` context. The local context is provided as `context`.
+	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		self.id.reanchor(target, context)
+	}
+
+	/// Mutate the location of the asset identifier if concrete, giving it the same location
+	/// relative to a `target` context. The local context is provided as `context`.
+	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
+		self.id.reanchor(target, context)?;
+		Ok(self)
+	}
+}
+
+impl TryFrom<OldAsset> for Asset {
+	type Error = ();
+	fn try_from(old: OldAsset) -> Result<Self, ()> {
+		Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? })
+	}
+}
+
+/// A `Vec` of `Asset`s.
+///
+/// There are a number of invariants which the construction and mutation functions must ensure are
+/// maintained:
+/// - It may contain no items of duplicate asset class;
+/// - All items must be ordered;
+/// - The number of items should grow no larger than `MAX_ITEMS_IN_ASSETS`.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	TypeInfo,
+	Default,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub struct Assets(Vec<Asset>);
+
+/// Maximum number of items we expect in a single `Assets` value. Note this is not (yet)
+/// enforced, and just serves to provide a sensible `max_encoded_len` for `Assets`.
+pub const MAX_ITEMS_IN_ASSETS: usize = 20;
+
+impl MaxEncodedLen for Assets {
+	fn max_encoded_len() -> usize {
+		Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS
+	}
+}
+
+impl Decode for Assets {
+	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
+		let bounded_instructions =
+			BoundedVec::<Asset, ConstU32<{ MAX_ITEMS_IN_ASSETS as u32 }>>::decode(input)?;
+		Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
+			.map_err(|()| "Out of order".into())
+	}
+}
+
+impl TryFrom<OldAssets> for Assets {
+	type Error = ();
+	fn try_from(old: OldAssets) -> Result<Self, ()> {
+		let v = old
+			.into_inner()
+			.into_iter()
+			.map(Asset::try_from)
+			.collect::<Result<Vec<_>, ()>>()?;
+		Ok(Assets(v))
+	}
+}
+
+impl From<Vec<Asset>> for Assets {
+	fn from(mut assets: Vec<Asset>) -> Self {
+		let mut res = Vec::with_capacity(assets.len());
+		if !assets.is_empty() {
+			assets.sort();
+			let mut iter = assets.into_iter();
+			if let Some(first) = iter.next() {
+				let last = iter.fold(first, |a, b| -> Asset {
+					match (a, b) {
+						(
+							Asset { fun: Fungibility::Fungible(a_amount), id: a_id },
+							Asset { fun: Fungibility::Fungible(b_amount), id: b_id },
+						) if a_id == b_id => Asset {
+							id: a_id,
+							fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)),
+						},
+						(
+							Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
+							Asset { fun: Fungibility::NonFungible(b_instance), id: b_id },
+						) if a_id == b_id && a_instance == b_instance =>
+							Asset { fun: Fungibility::NonFungible(a_instance), id: a_id },
+						(to_push, to_remember) => {
+							res.push(to_push);
+							to_remember
+						},
+					}
+				});
+				res.push(last);
+			}
+		}
+		Self(res)
+	}
+}
+
+impl<T: Into<Asset>> From<T> for Assets {
+	fn from(x: T) -> Self {
+		Self(vec![x.into()])
+	}
+}
+
+impl Assets {
+	/// A new (empty) value.
+	pub fn new() -> Self {
+		Self(Vec::new())
+	}
+
+	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
+	/// and which contain no duplicates.
+	///
+	/// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates.
+	/// If you can't guarantee that `r` is sorted and deduplicated, then use
+	/// `From::<Vec<Asset>>::from` which is infallible.
+	pub fn from_sorted_and_deduplicated(r: Vec<Asset>) -> Result<Self, ()> {
+		if r.is_empty() {
+			return Ok(Self(Vec::new()))
+		}
+		r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> {
+			if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) {
+				Ok(b)
+			} else {
+				Err(())
+			}
+		})?;
+		Ok(Self(r))
+	}
+
+	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
+	/// and which contain no duplicates.
+	///
+	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
+	/// negligible-cost operation. Generally though you should avoid using it unless you have a
+	/// strict proof that `r` is valid.
+	#[cfg(test)]
+	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
+		Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped")
+	}
+	/// Create a new instance of `Assets` from a `Vec<Asset>` whose contents are sorted
+	/// and which contain no duplicates.
+	///
+	/// In release mode, this skips any checks to ensure that `r` is correct, making it a
+	/// negligible-cost operation. Generally though you should avoid using it unless you have a
+	/// strict proof that `r` is valid.
+	///
+	/// In test mode, this checks anyway and panics on fail.
+	#[cfg(not(test))]
+	pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<Asset>) -> Self {
+		Self(r)
+	}
+
+	/// Add some asset onto the list, saturating. This is quite a laborious operation since it
+	/// maintains the ordering.
+	pub fn push(&mut self, a: Asset) {
+		for asset in self.0.iter_mut().filter(|x| x.id == a.id) {
+			match (&a.fun, &mut asset.fun) {
+				(Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => {
+					*balance = balance.saturating_add(*amount);
+					return
+				},
+				(Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2))
+					if inst1 == inst2 =>
+					return,
+				_ => (),
+			}
+		}
+		self.0.push(a);
+		self.0.sort();
+	}
+
+	/// Returns `true` if this definitely represents no asset.
+	pub fn is_none(&self) -> bool {
+		self.0.is_empty()
+	}
+
+	/// Returns true if `self` is a super-set of the given `inner` asset.
+	pub fn contains(&self, inner: &Asset) -> bool {
+		self.0.iter().any(|i| i.contains(inner))
+	}
+
+	/// Consume `self` and return the inner vec.
+	#[deprecated = "Use `into_inner()` instead"]
+	pub fn drain(self) -> Vec<Asset> {
+		self.0
+	}
+
+	/// Consume `self` and return the inner vec.
+	pub fn into_inner(self) -> Vec<Asset> {
+		self.0
+	}
+
+	/// Return a reference to the inner vec.
+	pub fn inner(&self) -> &Vec<Asset> {
+		&self.0
+	}
+
+	/// Return the number of distinct asset instances contained.
+	pub fn len(&self) -> usize {
+		self.0.len()
+	}
+
+	/// Prepend a `Location` to any concrete asset items, giving it a new root location.
+	pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> {
+		self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?;
+		self.0.sort();
+		Ok(())
+	}
+
+	/// Return a reference to an item at a specific index or `None` if it doesn't exist.
+	pub fn get(&self, index: usize) -> Option<&Asset> {
+		self.0.get(index)
+	}
+}
+
+impl Reanchorable for Assets {
+	type Error = ();
+
+	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?;
+		self.0.sort();
+		Ok(())
+	}
+
+	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, ()> {
+		match self.reanchor(target, context) {
+			Ok(()) => Ok(self),
+			Err(()) => Err(()),
+		}
+	}
+}
+
+/// A wildcard representing a set of assets.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum WildAsset {
+	/// All assets in Holding.
+	All,
+	/// All assets in Holding of a given fungibility and ID.
+	AllOf { id: AssetId, fun: WildFungibility },
+	/// All assets in Holding, up to `u32` individual assets (different instances of non-fungibles
+	/// are separate assets).
+	AllCounted(#[codec(compact)] u32),
+	/// All assets in Holding of a given fungibility and ID up to `count` individual assets
+	/// (different instances of non-fungibles are separate assets).
+	AllOfCounted {
+		id: AssetId,
+		fun: WildFungibility,
+		#[codec(compact)]
+		count: u32,
+	},
+}
+
+impl TryFrom<OldWildAsset> for WildAsset {
+	type Error = ();
+	fn try_from(old: OldWildAsset) -> Result<WildAsset, ()> {
+		use OldWildAsset::*;
+		Ok(match old {
+			AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? },
+			All => Self::All,
+			AllOfCounted { id, fun, count } =>
+				Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count },
+			AllCounted(count) => Self::AllCounted(count),
+		})
+	}
+}
+
+impl WildAsset {
+	/// Returns true if `self` is a super-set of the given `inner` asset.
+	pub fn contains(&self, inner: &Asset) -> bool {
+		use WildAsset::*;
+		match self {
+			AllOfCounted { count: 0, .. } | AllCounted(0) => false,
+			AllOf { fun, id } | AllOfCounted { id, fun, .. } =>
+				inner.fun.is_kind(*fun) && &inner.id == id,
+			All | AllCounted(_) => true,
+		}
+	}
+
+	/// Returns true if the wild element of `self` matches `inner`.
+	///
+	/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
+	/// always returning `false` when equal to 0.
+	#[deprecated = "Use `contains` instead"]
+	pub fn matches(&self, inner: &Asset) -> bool {
+		self.contains(inner)
+	}
+
+	/// Mutate the asset to represent the same value from the perspective of a new `target`
+	/// location. The local chain's location is provided in `context`.
+	pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		use WildAsset::*;
+		match self {
+			AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } =>
+				id.reanchor(target, context),
+			All | AllCounted(_) => Ok(()),
+		}
+	}
+
+	/// Maximum count of assets allowed to match, if any.
+	pub fn count(&self) -> Option<u32> {
+		use WildAsset::*;
+		match self {
+			AllOfCounted { count, .. } | AllCounted(count) => Some(*count),
+			All | AllOf { .. } => None,
+		}
+	}
+
+	/// Explicit limit on number of assets allowed to match, if any.
+	pub fn limit(&self) -> Option<u32> {
+		self.count()
+	}
+
+	/// Consume self and return the equivalent version but counted and with the `count` set to the
+	/// given parameter.
+	pub fn counted(self, count: u32) -> Self {
+		use WildAsset::*;
+		match self {
+			AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count },
+			All | AllCounted(_) => AllCounted(count),
+		}
+	}
+}
+
+impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildAsset {
+	fn from((id, fun): (A, B)) -> WildAsset {
+		WildAsset::AllOf { fun: fun.into(), id: id.into() }
+	}
+}
+
+/// `Asset` collection, defined either by a number of `Assets` or a single wildcard.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum AssetFilter {
+	/// Specify the filter as being everything contained by the given `Assets` inner.
+	Definite(Assets),
+	/// Specify the filter as the given `WildAsset` wildcard.
+	Wild(WildAsset),
+}
+
+impl<T: Into<WildAsset>> From<T> for AssetFilter {
+	fn from(x: T) -> Self {
+		Self::Wild(x.into())
+	}
+}
+
+impl From<Asset> for AssetFilter {
+	fn from(x: Asset) -> Self {
+		Self::Definite(vec![x].into())
+	}
+}
+
+impl From<Vec<Asset>> for AssetFilter {
+	fn from(x: Vec<Asset>) -> Self {
+		Self::Definite(x.into())
+	}
+}
+
+impl From<Assets> for AssetFilter {
+	fn from(x: Assets) -> Self {
+		Self::Definite(x)
+	}
+}
+
+impl AssetFilter {
+	/// Returns true if `inner` would be matched by `self`.
+	///
+	/// Note that for `Counted` variants of wildcards, then it will disregard the count except for
+	/// always returning `false` when equal to 0.
+	pub fn matches(&self, inner: &Asset) -> bool {
+		match self {
+			AssetFilter::Definite(ref assets) => assets.contains(inner),
+			AssetFilter::Wild(ref wild) => wild.contains(inner),
+		}
+	}
+
+	/// Mutate the location of the asset identifier if concrete, giving it the same location
+	/// relative to a `target` context. The local context is provided as `context`.
+	pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		match self {
+			AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context),
+			AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context),
+		}
+	}
+
+	/// Maximum count of assets it is possible to match, if known.
+	pub fn count(&self) -> Option<u32> {
+		use AssetFilter::*;
+		match self {
+			Definite(x) => Some(x.len() as u32),
+			Wild(x) => x.count(),
+		}
+	}
+
+	/// Explicit limit placed on the number of items, if any.
+	pub fn limit(&self) -> Option<u32> {
+		use AssetFilter::*;
+		match self {
+			Definite(_) => None,
+			Wild(x) => x.limit(),
+		}
+	}
+}
+
+impl TryFrom<OldAssetFilter> for AssetFilter {
+	type Error = ();
+	fn try_from(old: OldAssetFilter) -> Result<AssetFilter, ()> {
+		Ok(match old {
+			OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?),
+			OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?),
+		})
+	}
+}
+
+/// Matches assets based on inner `AssetFilter` and tags them for a specific type of asset transfer.
+/// Please note: the transfer type is specific to each particular `(asset, source, dest)`
+/// combination, so it should always be built in the context of `source` after knowing `dest`.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	Encode,
+	Decode,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum AssetTransferFilter {
+	/// teleport assets matching `AssetFilter` to a specific destination
+	Teleport(AssetFilter),
+	/// reserve-transfer assets matching `AssetFilter` to a specific destination, using the local
+	/// chain as reserve
+	ReserveDeposit(AssetFilter),
+	/// reserve-transfer assets matching `AssetFilter` to a specific destination, using the
+	/// destination as reserve
+	ReserveWithdraw(AssetFilter),
+}
+
+impl AssetTransferFilter {
+	/// Returns reference to inner `AssetFilter` ignoring the transfer type.
+	pub fn inner(&self) -> &AssetFilter {
+		match self {
+			AssetTransferFilter::Teleport(inner) => inner,
+			AssetTransferFilter::ReserveDeposit(inner) => inner,
+			AssetTransferFilter::ReserveWithdraw(inner) => inner,
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::super::prelude::*;
+
+	#[test]
+	fn conversion_works() {
+		let _: Assets = (Here, 1u128).into();
+	}
+
+	#[test]
+	fn from_sorted_and_deduplicated_works() {
+		use super::*;
+		use alloc::vec;
+
+		let empty = vec![];
+		let r = Assets::from_sorted_and_deduplicated(empty);
+		assert_eq!(r, Ok(Assets(vec![])));
+
+		let dup_fun = vec![(Here, 100).into(), (Here, 10).into()];
+		let r = Assets::from_sorted_and_deduplicated(dup_fun);
+		assert!(r.is_err());
+
+		let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()];
+		let r = Assets::from_sorted_and_deduplicated(dup_nft);
+		assert!(r.is_err());
+
+		let good_fun = vec![(Here, 10).into(), (Parent, 10).into()];
+		let r = Assets::from_sorted_and_deduplicated(good_fun.clone());
+		assert_eq!(r, Ok(Assets(good_fun)));
+
+		let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()];
+		let r = Assets::from_sorted_and_deduplicated(bad_fun);
+		assert!(r.is_err());
+
+		let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()];
+		let r = Assets::from_sorted_and_deduplicated(good_nft.clone());
+		assert_eq!(r, Ok(Assets(good_nft)));
+
+		let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()];
+		let r = Assets::from_sorted_and_deduplicated(bad_nft);
+		assert!(r.is_err());
+
+		let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()];
+		let r = Assets::from_sorted_and_deduplicated(mixed_good.clone());
+		assert_eq!(r, Ok(Assets(mixed_good)));
+
+		let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()];
+		let r = Assets::from_sorted_and_deduplicated(mixed_bad);
+		assert!(r.is_err());
+	}
+
+	#[test]
+	fn reanchor_preserves_sorting() {
+		use super::*;
+		use alloc::vec;
+
+		let reanchor_context: Junctions = Parachain(2000).into();
+		let dest = Location::new(1, []);
+
+		let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
+		let mut asset_1_reanchored = asset_1.clone();
+		assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok());
+		assert_eq!(
+			asset_1_reanchored,
+			(Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into()
+		);
+
+		let asset_2: Asset = (Location::new(1, []), 10).into();
+		let mut asset_2_reanchored = asset_2.clone();
+		assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok());
+		assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into());
+
+		let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into();
+		let mut asset_3_reanchored = asset_3.clone();
+		assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok());
+		assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into());
+
+		let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into();
+		assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into());
+
+		// decoding respects limits and sorting
+		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
+
+		assert!(assets.reanchor(&dest, &reanchor_context).is_ok());
+		assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]);
+
+		// decoding respects limits and sorting
+		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
+	}
+
+	#[test]
+	fn prepend_preserves_sorting() {
+		use super::*;
+		use alloc::vec;
+
+		let prefix = Location::new(0, [Parachain(1000)]);
+
+		let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into();
+		let mut asset_1_prepended = asset_1.clone();
+		assert!(asset_1_prepended.prepend_with(&prefix).is_ok());
+		// changes interior X2->X3
+		assert_eq!(
+			asset_1_prepended,
+			(Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into()
+		);
+
+		let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into();
+		let mut asset_2_prepended = asset_2.clone();
+		assert!(asset_2_prepended.prepend_with(&prefix).is_ok());
+		// changes parent
+		assert_eq!(
+			asset_2_prepended,
+			(Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into()
+		);
+
+		let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into();
+		let mut asset_3_prepended = asset_3.clone();
+		assert!(asset_3_prepended.prepend_with(&prefix).is_ok());
+		// changes parent
+		assert_eq!(
+			asset_3_prepended,
+			(Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into()
+		);
+
+		// `From` impl does sorting.
+		let mut assets: Assets = vec![asset_1, asset_2, asset_3].into();
+		// decoding respects limits and sorting
+		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
+
+		// let's do `prepend_with`
+		assert!(assets.prepend_with(&prefix).is_ok());
+		assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]);
+
+		// decoding respects limits and sorting
+		assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok());
+	}
+
+	#[test]
+	fn decoding_respects_limit() {
+		use super::*;
+
+		// Having lots of one asset will work since they are deduplicated
+		let lots_of_one_asset: Assets =
+			vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into();
+		let encoded = lots_of_one_asset.encode();
+		assert!(Assets::decode(&mut &encoded[..]).is_ok());
+
+		// Fewer assets than the limit works
+		let mut few_assets: Assets = Vec::new().into();
+		for i in 0..MAX_ITEMS_IN_ASSETS {
+			few_assets.push((GeneralIndex(i as u128), 1u128).into());
+		}
+		let encoded = few_assets.encode();
+		assert!(Assets::decode(&mut &encoded[..]).is_ok());
+
+		// Having lots of different assets will not work
+		let mut too_many_different_assets: Assets = Vec::new().into();
+		for i in 0..MAX_ITEMS_IN_ASSETS + 1 {
+			too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
+		}
+		let encoded = too_many_different_assets.encode();
+		assert!(Assets::decode(&mut &encoded[..]).is_err());
+	}
+}
diff --git a/polkadot/xcm/src/v5/junction.rs b/polkadot/xcm/src/v5/junction.rs
new file mode 100644
index 00000000000..952b61cd9ff
--- /dev/null
+++ b/polkadot/xcm/src/v5/junction.rs
@@ -0,0 +1,321 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Support data structures for `Location`, primarily the `Junction` datatype.
+
+use super::Location;
+pub use crate::v4::{BodyId, BodyPart};
+use crate::{
+	v4::{Junction as OldJunction, NetworkId as OldNetworkId},
+	VersionedLocation,
+};
+use bounded_collections::{BoundedSlice, BoundedVec, ConstU32};
+use codec::{self, Decode, Encode, MaxEncodedLen};
+use hex_literal::hex;
+use scale_info::TypeInfo;
+use serde::{Deserialize, Serialize};
+
+/// A single item in a path to describe the relative location of a consensus system.
+///
+/// Each item assumes a pre-existing location as its context and is defined in terms of it.
+#[derive(
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Encode,
+	Decode,
+	Debug,
+	TypeInfo,
+	MaxEncodedLen,
+	Serialize,
+	Deserialize,
+)]
+pub enum Junction {
+	/// An indexed parachain belonging to and operated by the context.
+	///
+	/// Generally used when the context is a Polkadot Relay-chain.
+	Parachain(#[codec(compact)] u32),
+	/// A 32-byte identifier for an account of a specific network that is respected as a sovereign
+	/// endpoint within the context.
+	///
+	/// Generally used when the context is a Substrate-based chain.
+	AccountId32 { network: Option<NetworkId>, id: [u8; 32] },
+	/// An 8-byte index for an account of a specific network that is respected as a sovereign
+	/// endpoint within the context.
+	///
+	/// May be used when the context is a Frame-based chain and includes e.g. an indices pallet.
+	AccountIndex64 {
+		network: Option<NetworkId>,
+		#[codec(compact)]
+		index: u64,
+	},
+	/// A 20-byte identifier for an account of a specific network that is respected as a sovereign
+	/// endpoint within the context.
+	///
+	/// May be used when the context is an Ethereum or Bitcoin chain or smart-contract.
+	AccountKey20 { network: Option<NetworkId>, key: [u8; 20] },
+	/// An instanced, indexed pallet that forms a constituent part of the context.
+	///
+	/// Generally used when the context is a Frame-based chain.
+	PalletInstance(u8),
+	/// A non-descript index within the context location.
+	///
+	/// Usage will vary widely owing to its generality.
+	///
+	/// NOTE: Try to avoid using this and instead use a more specific item.
+	GeneralIndex(#[codec(compact)] u128),
+	/// A nondescript array datum, 32 bytes, acting as a key within the context
+	/// location.
+	///
+	/// Usage will vary widely owing to its generality.
+	///
+	/// NOTE: Try to avoid using this and instead use a more specific item.
+	// Note this is implemented as an array with a length rather than using `BoundedVec` owing to
+	// the bound for `Copy`.
+	GeneralKey { length: u8, data: [u8; 32] },
+	/// The unambiguous child.
+	///
+	/// Not currently used except as a fallback when deriving context.
+	OnlyChild,
+	/// A pluralistic body existing within consensus.
+	///
+	/// Typical to be used to represent a governance origin of a chain, but could in principle be
+	/// used to represent things such as multisigs also.
+	Plurality { id: BodyId, part: BodyPart },
+	/// A global network capable of externalizing its own consensus. This is not generally
+	/// meaningful outside of the universal level.
+	GlobalConsensus(NetworkId),
+}
+
+/// The genesis hash of the Westend testnet. Used to identify it.
+pub const WESTEND_GENESIS_HASH: [u8; 32] =
+	hex!["e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e"];
+
+/// The genesis hash of the Rococo testnet. Used to identify it.
+pub const ROCOCO_GENESIS_HASH: [u8; 32] =
+	hex!["6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e"];
+
+/// Dummy genesis hash used instead of defunct networks like Wococo (and soon Rococo).
+pub const DUMMY_GENESIS_HASH: [u8; 32] = [0; 32];
+
+/// A global identifier of a data structure existing within consensus.
+///
+/// Maintenance note: Networks with global consensus and which are practically bridgeable within the
+/// Polkadot ecosystem are given preference over explicit naming in this enumeration.
+#[derive(
+	Copy,
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Encode,
+	Decode,
+	Debug,
+	TypeInfo,
+	MaxEncodedLen,
+	Serialize,
+	Deserialize,
+)]
+pub enum NetworkId {
+	/// Network specified by the first 32 bytes of its genesis block.
+	ByGenesis([u8; 32]),
+	/// Network defined by the first 32-bytes of the hash and number of some block it contains.
+	ByFork { block_number: u64, block_hash: [u8; 32] },
+	/// The Polkadot mainnet Relay-chain.
+	Polkadot,
+	/// The Kusama canary-net Relay-chain.
+	Kusama,
+	/// An Ethereum network specified by its chain ID.
+	Ethereum {
+		/// The EIP-155 chain ID.
+		#[codec(compact)]
+		chain_id: u64,
+	},
+	/// The Bitcoin network, including hard-forks supported by Bitcoin Core development team.
+	BitcoinCore,
+	/// The Bitcoin network, including hard-forks supported by Bitcoin Cash developers.
+	BitcoinCash,
+	/// The Polkadot Bulletin chain.
+	PolkadotBulletin,
+}
+
+impl From<OldNetworkId> for Option<NetworkId> {
+	fn from(old: OldNetworkId) -> Self {
+		Some(NetworkId::from(old))
+	}
+}
+
+impl From<OldNetworkId> for NetworkId {
+	fn from(old: OldNetworkId) -> Self {
+		use OldNetworkId::*;
+		match old {
+			ByGenesis(hash) => Self::ByGenesis(hash),
+			ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
+			Polkadot => Self::Polkadot,
+			Kusama => Self::Kusama,
+			Westend => Self::ByGenesis(WESTEND_GENESIS_HASH),
+			Rococo => Self::ByGenesis(ROCOCO_GENESIS_HASH),
+			Wococo => Self::ByGenesis(DUMMY_GENESIS_HASH),
+			Ethereum { chain_id } => Self::Ethereum { chain_id },
+			BitcoinCore => Self::BitcoinCore,
+			BitcoinCash => Self::BitcoinCash,
+			PolkadotBulletin => Self::PolkadotBulletin,
+		}
+	}
+}
+
+impl From<NetworkId> for Junction {
+	fn from(n: NetworkId) -> Self {
+		Self::GlobalConsensus(n)
+	}
+}
+
+impl From<[u8; 32]> for Junction {
+	fn from(id: [u8; 32]) -> Self {
+		Self::AccountId32 { network: None, id }
+	}
+}
+
+impl From<BoundedVec<u8, ConstU32<32>>> for Junction {
+	fn from(key: BoundedVec<u8, ConstU32<32>>) -> Self {
+		key.as_bounded_slice().into()
+	}
+}
+
+impl<'a> From<BoundedSlice<'a, u8, ConstU32<32>>> for Junction {
+	fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self {
+		let mut data = [0u8; 32];
+		data[..key.len()].copy_from_slice(&key[..]);
+		Self::GeneralKey { length: key.len() as u8, data }
+	}
+}
+
+impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> {
+	type Error = ();
+	fn try_from(key: &'a Junction) -> Result<Self, ()> {
+		match key {
+			Junction::GeneralKey { length, data } =>
+				BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()),
+			_ => Err(()),
+		}
+	}
+}
+
+impl From<[u8; 20]> for Junction {
+	fn from(key: [u8; 20]) -> Self {
+		Self::AccountKey20 { network: None, key }
+	}
+}
+
+impl From<u64> for Junction {
+	fn from(index: u64) -> Self {
+		Self::AccountIndex64 { network: None, index }
+	}
+}
+
+impl From<u128> for Junction {
+	fn from(id: u128) -> Self {
+		Self::GeneralIndex(id)
+	}
+}
+
+impl TryFrom<OldJunction> for Junction {
+	type Error = ();
+	fn try_from(value: OldJunction) -> Result<Self, ()> {
+		use OldJunction::*;
+		Ok(match value {
+			Parachain(id) => Self::Parachain(id),
+			AccountId32 { network: maybe_network, id } =>
+				Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
+			AccountIndex64 { network: maybe_network, index } =>
+				Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
+			AccountKey20 { network: maybe_network, key } =>
+				Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
+			PalletInstance(index) => Self::PalletInstance(index),
+			GeneralIndex(id) => Self::GeneralIndex(id),
+			GeneralKey { length, data } => Self::GeneralKey { length, data },
+			OnlyChild => Self::OnlyChild,
+			Plurality { id, part } => Self::Plurality { id, part },
+			GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
+		})
+	}
+}
+
+impl Junction {
+	/// Convert `self` into a `Location` containing 0 parents.
+	///
+	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
+	pub fn into_location(self) -> Location {
+		Location::new(0, [self])
+	}
+
+	/// Convert `self` into a `Location` containing `n` parents.
+	///
+	/// Similar to `Self::into_location`, with the added ability to specify the number of parent
+	/// junctions.
+	pub fn into_exterior(self, n: u8) -> Location {
+		Location::new(n, [self])
+	}
+
+	/// Convert `self` into a `VersionedLocation` containing 0 parents.
+	///
+	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
+	pub fn into_versioned(self) -> VersionedLocation {
+		self.into_location().into_versioned()
+	}
+
+	/// Remove the `NetworkId` value.
+	pub fn remove_network_id(&mut self) {
+		use Junction::*;
+		match self {
+			AccountId32 { ref mut network, .. } |
+			AccountIndex64 { ref mut network, .. } |
+			AccountKey20 { ref mut network, .. } => *network = None,
+			_ => {},
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use alloc::vec;
+
+	#[test]
+	fn junction_round_trip_works() {
+		let j = Junction::GeneralKey { length: 32, data: [1u8; 32] };
+		let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
+		assert_eq!(j, k);
+
+		let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
+		let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
+		assert_eq!(j, k);
+
+		let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap());
+		let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
+		assert_eq!(j, k);
+		let s: BoundedSlice<_, _> = (&k).try_into().unwrap();
+		assert_eq!(s, &[1u8, 2, 3, 4][..]);
+
+		let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
+		let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
+		assert_eq!(j, k);
+	}
+}
diff --git a/polkadot/xcm/src/v5/junctions.rs b/polkadot/xcm/src/v5/junctions.rs
new file mode 100644
index 00000000000..dc93c541d19
--- /dev/null
+++ b/polkadot/xcm/src/v5/junctions.rs
@@ -0,0 +1,723 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! XCM `Junctions`/`InteriorLocation` datatype.
+
+use super::{Junction, Location, NetworkId};
+use alloc::sync::Arc;
+use codec::{Decode, Encode, MaxEncodedLen};
+use core::{mem, ops::Range, result};
+use scale_info::TypeInfo;
+
+/// Maximum number of `Junction`s that a `Junctions` can contain.
+pub(crate) const MAX_JUNCTIONS: usize = 8;
+
+/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
+/// implementation uses a Rust `enum` in order to make pattern matching easier.
+///
+/// Parent junctions cannot be constructed with this type. Refer to `Location` for
+/// instructions on constructing parent junctions.
+#[derive(
+	Clone,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Encode,
+	Decode,
+	Debug,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub enum Junctions {
+	/// The interpreting consensus system.
+	Here,
+	/// A relative path comprising 1 junction.
+	X1(Arc<[Junction; 1]>),
+	/// A relative path comprising 2 junctions.
+	X2(Arc<[Junction; 2]>),
+	/// A relative path comprising 3 junctions.
+	X3(Arc<[Junction; 3]>),
+	/// A relative path comprising 4 junctions.
+	X4(Arc<[Junction; 4]>),
+	/// A relative path comprising 5 junctions.
+	X5(Arc<[Junction; 5]>),
+	/// A relative path comprising 6 junctions.
+	X6(Arc<[Junction; 6]>),
+	/// A relative path comprising 7 junctions.
+	X7(Arc<[Junction; 7]>),
+	/// A relative path comprising 8 junctions.
+	X8(Arc<[Junction; 8]>),
+}
+
+macro_rules! impl_junctions {
+	($count:expr, $variant:ident) => {
+		impl From<[Junction; $count]> for Junctions {
+			fn from(junctions: [Junction; $count]) -> Self {
+				Self::$variant(Arc::new(junctions))
+			}
+		}
+		impl PartialEq<[Junction; $count]> for Junctions {
+			fn eq(&self, rhs: &[Junction; $count]) -> bool {
+				self.as_slice() == rhs
+			}
+		}
+	};
+}
+
+impl_junctions!(1, X1);
+impl_junctions!(2, X2);
+impl_junctions!(3, X3);
+impl_junctions!(4, X4);
+impl_junctions!(5, X5);
+impl_junctions!(6, X6);
+impl_junctions!(7, X7);
+impl_junctions!(8, X8);
+
+pub struct JunctionsIterator {
+	junctions: Junctions,
+	range: Range<usize>,
+}
+
+impl Iterator for JunctionsIterator {
+	type Item = Junction;
+	fn next(&mut self) -> Option<Junction> {
+		self.junctions.at(self.range.next()?).cloned()
+	}
+}
+
+impl DoubleEndedIterator for JunctionsIterator {
+	fn next_back(&mut self) -> Option<Junction> {
+		self.junctions.at(self.range.next_back()?).cloned()
+	}
+}
+
+pub struct JunctionsRefIterator<'a> {
+	junctions: &'a Junctions,
+	range: Range<usize>,
+}
+
+impl<'a> Iterator for JunctionsRefIterator<'a> {
+	type Item = &'a Junction;
+	fn next(&mut self) -> Option<&'a Junction> {
+		self.junctions.at(self.range.next()?)
+	}
+}
+
+impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
+	fn next_back(&mut self) -> Option<&'a Junction> {
+		self.junctions.at(self.range.next_back()?)
+	}
+}
+impl<'a> IntoIterator for &'a Junctions {
+	type Item = &'a Junction;
+	type IntoIter = JunctionsRefIterator<'a>;
+	fn into_iter(self) -> Self::IntoIter {
+		JunctionsRefIterator { junctions: self, range: 0..self.len() }
+	}
+}
+
+impl IntoIterator for Junctions {
+	type Item = Junction;
+	type IntoIter = JunctionsIterator;
+	fn into_iter(self) -> Self::IntoIter {
+		JunctionsIterator { range: 0..self.len(), junctions: self }
+	}
+}
+
+impl Junctions {
+	/// Convert `self` into a `Location` containing 0 parents.
+	///
+	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
+	pub const fn into_location(self) -> Location {
+		Location { parents: 0, interior: self }
+	}
+
+	/// Convert `self` into a `Location` containing `n` parents.
+	///
+	/// Similar to `Self::into_location`, with the added ability to specify the number of parent
+	/// junctions.
+	pub const fn into_exterior(self, n: u8) -> Location {
+		Location { parents: n, interior: self }
+	}
+
+	/// Casts `self` into a slice containing `Junction`s.
+	pub fn as_slice(&self) -> &[Junction] {
+		match self {
+			Junctions::Here => &[],
+			Junctions::X1(ref a) => &a[..],
+			Junctions::X2(ref a) => &a[..],
+			Junctions::X3(ref a) => &a[..],
+			Junctions::X4(ref a) => &a[..],
+			Junctions::X5(ref a) => &a[..],
+			Junctions::X6(ref a) => &a[..],
+			Junctions::X7(ref a) => &a[..],
+			Junctions::X8(ref a) => &a[..],
+		}
+	}
+
+	/// Casts `self` into a mutable slice containing `Junction`s.
+	pub fn as_slice_mut(&mut self) -> &mut [Junction] {
+		match self {
+			Junctions::Here => &mut [],
+			Junctions::X1(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X2(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X3(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X4(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X5(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X6(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X7(ref mut a) => &mut Arc::make_mut(a)[..],
+			Junctions::X8(ref mut a) => &mut Arc::make_mut(a)[..],
+		}
+	}
+
+	/// Remove the `NetworkId` value in any `Junction`s.
+	pub fn remove_network_id(&mut self) {
+		self.for_each_mut(Junction::remove_network_id);
+	}
+
+	/// Treating `self` as the universal context, return the location of the local consensus system
+	/// from the point of view of the given `target`.
+	pub fn invert_target(&self, target: &Location) -> Result<Location, ()> {
+		let mut itself = self.clone();
+		let mut junctions = Self::Here;
+		for _ in 0..target.parent_count() {
+			junctions = junctions
+				.pushed_front_with(itself.take_last().unwrap_or(Junction::OnlyChild))
+				.map_err(|_| ())?;
+		}
+		let parents = target.interior().len() as u8;
+		Ok(Location::new(parents, junctions))
+	}
+
+	/// Execute a function `f` on every junction. We use this since we cannot implement a mutable
+	/// `Iterator` without unsafe code.
+	pub fn for_each_mut(&mut self, x: impl FnMut(&mut Junction)) {
+		self.as_slice_mut().iter_mut().for_each(x)
+	}
+
+	/// Extract the network ID treating this value as a universal location.
+	///
+	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
+	/// that this value is not a universal location.
+	pub fn global_consensus(&self) -> Result<NetworkId, ()> {
+		if let Some(Junction::GlobalConsensus(network)) = self.first() {
+			Ok(*network)
+		} else {
+			Err(())
+		}
+	}
+
+	/// Extract the network ID and the interior consensus location, treating this value as a
+	/// universal location.
+	///
+	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
+	/// that this value is not a universal location.
+	pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> {
+		match self.split_first() {
+			(location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)),
+			_ => return Err(()),
+		}
+	}
+
+	/// Treat `self` as a universal location and the context of `relative`, returning the universal
+	/// location of relative.
+	///
+	/// This will return an error if `relative` has as many (or more) parents than there are
+	/// junctions in `self`, implying that relative refers into a different global consensus.
+	pub fn within_global(mut self, relative: Location) -> Result<Self, ()> {
+		if self.len() <= relative.parent_count() as usize {
+			return Err(())
+		}
+		for _ in 0..relative.parent_count() {
+			self.take_last();
+		}
+		for j in relative.interior() {
+			self.push(*j).map_err(|_| ())?;
+		}
+		Ok(self)
+	}
+
+	/// Consumes `self` and returns how `viewer` would address it locally.
+	pub fn relative_to(mut self, viewer: &Junctions) -> Location {
+		let mut i = 0;
+		while match (self.first(), viewer.at(i)) {
+			(Some(x), Some(y)) => x == y,
+			_ => false,
+		} {
+			self = self.split_first().0;
+			// NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times.
+			i += 1;
+		}
+		// AUDIT NOTES:
+		// - above loop ensures that `i <= viewer.len()`.
+		// - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`.
+		Location::new((viewer.len() - i) as u8, self)
+	}
+
+	/// Returns first junction, or `None` if the location is empty.
+	pub fn first(&self) -> Option<&Junction> {
+		self.as_slice().first()
+	}
+
+	/// Returns last junction, or `None` if the location is empty.
+	pub fn last(&self) -> Option<&Junction> {
+		self.as_slice().last()
+	}
+
+	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
+	/// first element (second item in tuple) or `None` if it was empty.
+	pub fn split_first(self) -> (Junctions, Option<Junction>) {
+		match self {
+			Junctions::Here => (Junctions::Here, None),
+			Junctions::X1(xs) => {
+				let [a] = *xs;
+				(Junctions::Here, Some(a))
+			},
+			Junctions::X2(xs) => {
+				let [a, b] = *xs;
+				([b].into(), Some(a))
+			},
+			Junctions::X3(xs) => {
+				let [a, b, c] = *xs;
+				([b, c].into(), Some(a))
+			},
+			Junctions::X4(xs) => {
+				let [a, b, c, d] = *xs;
+				([b, c, d].into(), Some(a))
+			},
+			Junctions::X5(xs) => {
+				let [a, b, c, d, e] = *xs;
+				([b, c, d, e].into(), Some(a))
+			},
+			Junctions::X6(xs) => {
+				let [a, b, c, d, e, f] = *xs;
+				([b, c, d, e, f].into(), Some(a))
+			},
+			Junctions::X7(xs) => {
+				let [a, b, c, d, e, f, g] = *xs;
+				([b, c, d, e, f, g].into(), Some(a))
+			},
+			Junctions::X8(xs) => {
+				let [a, b, c, d, e, f, g, h] = *xs;
+				([b, c, d, e, f, g, h].into(), Some(a))
+			},
+		}
+	}
+
+	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
+	/// last element (second item in tuple) or `None` if it was empty.
+	pub fn split_last(self) -> (Junctions, Option<Junction>) {
+		match self {
+			Junctions::Here => (Junctions::Here, None),
+			Junctions::X1(xs) => {
+				let [a] = *xs;
+				(Junctions::Here, Some(a))
+			},
+			Junctions::X2(xs) => {
+				let [a, b] = *xs;
+				([a].into(), Some(b))
+			},
+			Junctions::X3(xs) => {
+				let [a, b, c] = *xs;
+				([a, b].into(), Some(c))
+			},
+			Junctions::X4(xs) => {
+				let [a, b, c, d] = *xs;
+				([a, b, c].into(), Some(d))
+			},
+			Junctions::X5(xs) => {
+				let [a, b, c, d, e] = *xs;
+				([a, b, c, d].into(), Some(e))
+			},
+			Junctions::X6(xs) => {
+				let [a, b, c, d, e, f] = *xs;
+				([a, b, c, d, e].into(), Some(f))
+			},
+			Junctions::X7(xs) => {
+				let [a, b, c, d, e, f, g] = *xs;
+				([a, b, c, d, e, f].into(), Some(g))
+			},
+			Junctions::X8(xs) => {
+				let [a, b, c, d, e, f, g, h] = *xs;
+				([a, b, c, d, e, f, g].into(), Some(h))
+			},
+		}
+	}
+
+	/// Removes the first element from `self`, returning it (or `None` if it was empty).
+	pub fn take_first(&mut self) -> Option<Junction> {
+		let mut d = Junctions::Here;
+		mem::swap(&mut *self, &mut d);
+		let (tail, head) = d.split_first();
+		*self = tail;
+		head
+	}
+
+	/// Removes the last element from `self`, returning it (or `None` if it was empty).
+	pub fn take_last(&mut self) -> Option<Junction> {
+		let mut d = Junctions::Here;
+		mem::swap(&mut *self, &mut d);
+		let (head, tail) = d.split_last();
+		*self = head;
+		tail
+	}
+
+	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
+	pub fn push(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
+		let new = new.into();
+		let mut dummy = Junctions::Here;
+		mem::swap(self, &mut dummy);
+		match dummy.pushed_with(new) {
+			Ok(s) => {
+				*self = s;
+				Ok(())
+			},
+			Err((s, j)) => {
+				*self = s;
+				Err(j)
+			},
+		}
+	}
+
+	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
+	pub fn push_front(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
+		let new = new.into();
+		let mut dummy = Junctions::Here;
+		mem::swap(self, &mut dummy);
+		match dummy.pushed_front_with(new) {
+			Ok(s) => {
+				*self = s;
+				Ok(())
+			},
+			Err((s, j)) => {
+				*self = s;
+				Err(j)
+			},
+		}
+	}
+
+	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
+	/// original value of `self` and `new` in case of overflow.
+	pub fn pushed_with(self, new: impl Into<Junction>) -> result::Result<Self, (Self, Junction)> {
+		let new = new.into();
+		Ok(match self {
+			Junctions::Here => [new].into(),
+			Junctions::X1(xs) => {
+				let [a] = *xs;
+				[a, new].into()
+			},
+			Junctions::X2(xs) => {
+				let [a, b] = *xs;
+				[a, b, new].into()
+			},
+			Junctions::X3(xs) => {
+				let [a, b, c] = *xs;
+				[a, b, c, new].into()
+			},
+			Junctions::X4(xs) => {
+				let [a, b, c, d] = *xs;
+				[a, b, c, d, new].into()
+			},
+			Junctions::X5(xs) => {
+				let [a, b, c, d, e] = *xs;
+				[a, b, c, d, e, new].into()
+			},
+			Junctions::X6(xs) => {
+				let [a, b, c, d, e, f] = *xs;
+				[a, b, c, d, e, f, new].into()
+			},
+			Junctions::X7(xs) => {
+				let [a, b, c, d, e, f, g] = *xs;
+				[a, b, c, d, e, f, g, new].into()
+			},
+			s => Err((s, new))?,
+		})
+	}
+
+	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
+	/// original value of `self` and `new` in case of overflow.
+	pub fn pushed_front_with(
+		self,
+		new: impl Into<Junction>,
+	) -> result::Result<Self, (Self, Junction)> {
+		let new = new.into();
+		Ok(match self {
+			Junctions::Here => [new].into(),
+			Junctions::X1(xs) => {
+				let [a] = *xs;
+				[new, a].into()
+			},
+			Junctions::X2(xs) => {
+				let [a, b] = *xs;
+				[new, a, b].into()
+			},
+			Junctions::X3(xs) => {
+				let [a, b, c] = *xs;
+				[new, a, b, c].into()
+			},
+			Junctions::X4(xs) => {
+				let [a, b, c, d] = *xs;
+				[new, a, b, c, d].into()
+			},
+			Junctions::X5(xs) => {
+				let [a, b, c, d, e] = *xs;
+				[new, a, b, c, d, e].into()
+			},
+			Junctions::X6(xs) => {
+				let [a, b, c, d, e, f] = *xs;
+				[new, a, b, c, d, e, f].into()
+			},
+			Junctions::X7(xs) => {
+				let [a, b, c, d, e, f, g] = *xs;
+				[new, a, b, c, d, e, f, g].into()
+			},
+			s => Err((s, new))?,
+		})
+	}
+
+	/// Mutate `self` so that it is suffixed with `suffix`.
+	///
+	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions, Junction::*, Location};
+	/// # fn main() {
+	/// let mut m = Junctions::from([Parachain(21)]);
+	/// assert_eq!(m.append_with([PalletInstance(3)]), Ok(()));
+	/// assert_eq!(m, [Parachain(21), PalletInstance(3)]);
+	/// # }
+	/// ```
+	pub fn append_with(&mut self, suffix: impl Into<Junctions>) -> Result<(), Junctions> {
+		let suffix = suffix.into();
+		if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
+			return Err(suffix)
+		}
+		for j in suffix.into_iter() {
+			self.push(j).expect("Already checked the sum of the len()s; qed")
+		}
+		Ok(())
+	}
+
+	/// Returns the number of junctions in `self`.
+	pub fn len(&self) -> usize {
+		self.as_slice().len()
+	}
+
+	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
+	/// elements.
+	pub fn at(&self, i: usize) -> Option<&Junction> {
+		self.as_slice().get(i)
+	}
+
+	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
+	/// contain that many elements.
+	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
+		self.as_slice_mut().get_mut(i)
+	}
+
+	/// Returns a reference iterator over the junctions.
+	pub fn iter(&self) -> JunctionsRefIterator {
+		JunctionsRefIterator { junctions: self, range: 0..self.len() }
+	}
+
+	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
+	/// If so, returns a reference to this `Junction` item.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions, Junction::*};
+	/// # fn main() {
+	/// let mut m = Junctions::from([Parachain(2), PalletInstance(3), OnlyChild]);
+	/// assert_eq!(m.match_and_split(&[Parachain(2), PalletInstance(3)].into()), Some(&OnlyChild));
+	/// assert_eq!(m.match_and_split(&[Parachain(2)].into()), None);
+	/// # }
+	/// ```
+	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
+		if prefix.len() + 1 != self.len() {
+			return None
+		}
+		for i in 0..prefix.len() {
+			if prefix.at(i) != self.at(i) {
+				return None
+			}
+		}
+		return self.at(prefix.len())
+	}
+
+	pub fn starts_with(&self, prefix: &Junctions) -> bool {
+		prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y)
+	}
+}
+
+impl TryFrom<Location> for Junctions {
+	type Error = Location;
+	fn try_from(x: Location) -> result::Result<Self, Location> {
+		if x.parent_count() > 0 {
+			Err(x)
+		} else {
+			Ok(x.interior().clone())
+		}
+	}
+}
+
+impl<T: Into<Junction>> From<T> for Junctions {
+	fn from(x: T) -> Self {
+		[x.into()].into()
+	}
+}
+
+impl From<[Junction; 0]> for Junctions {
+	fn from(_: [Junction; 0]) -> Self {
+		Self::Here
+	}
+}
+
+impl From<()> for Junctions {
+	fn from(_: ()) -> Self {
+		Self::Here
+	}
+}
+
+xcm_procedural::impl_conversion_functions_for_junctions_v5!();
+
+#[cfg(test)]
+mod tests {
+	use super::{super::prelude::*, *};
+
+	#[test]
+	fn inverting_works() {
+		let context: InteriorLocation = (Parachain(1000), PalletInstance(42)).into();
+		let target = (Parent, PalletInstance(69)).into();
+		let expected = (Parent, PalletInstance(42)).into();
+		let inverted = context.invert_target(&target).unwrap();
+		assert_eq!(inverted, expected);
+
+		let context: InteriorLocation =
+			(Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
+		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
+		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
+		let inverted = context.invert_target(&target).unwrap();
+		assert_eq!(inverted, expected);
+	}
+
+	#[test]
+	fn relative_to_works() {
+		use NetworkId::*;
+		assert_eq!(
+			Junctions::from([Polkadot.into()]).relative_to(&Junctions::from([Kusama.into()])),
+			(Parent, Polkadot).into()
+		);
+		let base = Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]);
+
+		// Ancestors.
+		assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into());
+		assert_eq!(Junctions::from([Kusama.into()]).relative_to(&base), (Parent, Parent).into());
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(1)]).relative_to(&base),
+			(Parent,).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]).relative_to(&base),
+			Here.into()
+		);
+
+		// Ancestors with one child.
+		assert_eq!(
+			Junctions::from([Polkadot.into()]).relative_to(&base),
+			(Parent, Parent, Parent, Polkadot).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(2)]).relative_to(&base),
+			(Parent, Parent, Parachain(2)).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2)]).relative_to(&base),
+			(Parent, PalletInstance(2)).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()])
+				.relative_to(&base),
+			([1u8; 32],).into()
+		);
+
+		// Ancestors with grandchildren.
+		assert_eq!(
+			Junctions::from([Polkadot.into(), Parachain(1)]).relative_to(&base),
+			(Parent, Parent, Parent, Polkadot, Parachain(1)).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(2), PalletInstance(1)]).relative_to(&base),
+			(Parent, Parent, Parachain(2), PalletInstance(1)).into()
+		);
+		assert_eq!(
+			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()])
+				.relative_to(&base),
+			(Parent, PalletInstance(2), [1u8; 32]).into()
+		);
+		assert_eq!(
+			Junctions::from([
+				Kusama.into(),
+				Parachain(1),
+				PalletInstance(1),
+				[1u8; 32].into(),
+				1u128.into()
+			])
+			.relative_to(&base),
+			([1u8; 32], 1u128).into()
+		);
+	}
+
+	#[test]
+	fn global_consensus_works() {
+		use NetworkId::*;
+		assert_eq!(Junctions::from([Polkadot.into()]).global_consensus(), Ok(Polkadot));
+		assert_eq!(Junctions::from([Kusama.into(), 1u64.into()]).global_consensus(), Ok(Kusama));
+		assert_eq!(Here.global_consensus(), Err(()));
+		assert_eq!(Junctions::from([1u64.into()]).global_consensus(), Err(()));
+		assert_eq!(Junctions::from([1u64.into(), Kusama.into()]).global_consensus(), Err(()));
+	}
+
+	#[test]
+	fn test_conversion() {
+		use super::{Junction::*, NetworkId::*};
+		let x: Junctions = GlobalConsensus(Polkadot).into();
+		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)]));
+		let x: Junctions = Polkadot.into();
+		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)]));
+		let x: Junctions = (Polkadot, Kusama).into();
+		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot), GlobalConsensus(Kusama)]));
+	}
+
+	#[test]
+	fn encode_decode_junctions_works() {
+		let original = Junctions::from([
+			Polkadot.into(),
+			Kusama.into(),
+			1u64.into(),
+			GlobalConsensus(Polkadot),
+			Parachain(123),
+			PalletInstance(45),
+		]);
+		let encoded = original.encode();
+		assert_eq!(encoded, &[6, 9, 2, 9, 3, 2, 0, 4, 9, 2, 0, 237, 1, 4, 45]);
+		let decoded = Junctions::decode(&mut &encoded[..]).unwrap();
+		assert_eq!(decoded, original);
+	}
+}
diff --git a/polkadot/xcm/src/v5/location.rs b/polkadot/xcm/src/v5/location.rs
new file mode 100644
index 00000000000..38e8ecdd15c
--- /dev/null
+++ b/polkadot/xcm/src/v5/location.rs
@@ -0,0 +1,755 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! XCM `Location` datatype.
+
+use super::{traits::Reanchorable, Junction, Junctions};
+use crate::{v4::Location as OldLocation, VersionedLocation};
+use codec::{Decode, Encode, MaxEncodedLen};
+use core::result;
+use scale_info::TypeInfo;
+
+/// A relative path between state-bearing consensus systems.
+///
+/// A location in a consensus system is defined as an *isolatable state machine* held within global
+/// consensus. The location in question need not have a sophisticated consensus algorithm of its
+/// own; a single account within Ethereum, for example, could be considered a location.
+///
+/// A very-much non-exhaustive list of types of location include:
+/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
+/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
+/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
+/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based
+///   Substrate chain.
+/// - An account.
+///
+/// A `Location` is a *relative identifier*, meaning that it can only be used to define the
+/// relative path between two locations, and cannot generally be used to refer to a location
+/// universally. It is comprised of an integer number of parents specifying the number of times to
+/// "escape" upwards into the containing consensus system and then a number of *junctions*, each
+/// diving down and specifying some interior portion of state (which may be considered a
+/// "sub-consensus" system).
+///
+/// This specific `Location` implementation uses a `Junctions` datatype which is a Rust `enum`
+/// in order to make pattern matching easier. There are occasions where it is important to ensure
+/// that a value is strictly an interior location, in those cases, `Junctions` may be used.
+///
+/// The `Location` value of `Null` simply refers to the interpreting consensus system.
+#[derive(
+	Clone,
+	Decode,
+	Encode,
+	Eq,
+	PartialEq,
+	Ord,
+	PartialOrd,
+	Debug,
+	TypeInfo,
+	MaxEncodedLen,
+	serde::Serialize,
+	serde::Deserialize,
+)]
+pub struct Location {
+	/// The number of parent junctions at the beginning of this `Location`.
+	pub parents: u8,
+	/// The interior (i.e. non-parent) junctions that this `Location` contains.
+	pub interior: Junctions,
+}
+
+impl Default for Location {
+	fn default() -> Self {
+		Self::here()
+	}
+}
+
+/// A relative location which is constrained to be an interior location of the context.
+///
+/// See also `Location`.
+pub type InteriorLocation = Junctions;
+
+impl Location {
+	/// Creates a new `Location` with the given number of parents and interior junctions.
+	pub fn new(parents: u8, interior: impl Into<Junctions>) -> Location {
+		Location { parents, interior: interior.into() }
+	}
+
+	/// Consume `self` and return the equivalent `VersionedLocation` value.
+	pub const fn into_versioned(self) -> VersionedLocation {
+		VersionedLocation::V5(self)
+	}
+
+	/// Creates a new `Location` with 0 parents and a `Here` interior.
+	///
+	/// The resulting `Location` can be interpreted as the "current consensus system".
+	pub const fn here() -> Location {
+		Location { parents: 0, interior: Junctions::Here }
+	}
+
+	/// Creates a new `Location` which evaluates to the parent context.
+	pub const fn parent() -> Location {
+		Location { parents: 1, interior: Junctions::Here }
+	}
+
+	/// Creates a new `Location` with `parents` and an empty (`Here`) interior.
+	pub const fn ancestor(parents: u8) -> Location {
+		Location { parents, interior: Junctions::Here }
+	}
+
+	/// Whether the `Location` has no parents and has a `Here` interior.
+	pub fn is_here(&self) -> bool {
+		self.parents == 0 && self.interior.len() == 0
+	}
+
+	/// Remove the `NetworkId` value in any interior `Junction`s.
+	pub fn remove_network_id(&mut self) {
+		self.interior.remove_network_id();
+	}
+
+	/// Return a reference to the interior field.
+	pub fn interior(&self) -> &Junctions {
+		&self.interior
+	}
+
+	/// Return a mutable reference to the interior field.
+	pub fn interior_mut(&mut self) -> &mut Junctions {
+		&mut self.interior
+	}
+
+	/// Returns the number of `Parent` junctions at the beginning of `self`.
+	pub const fn parent_count(&self) -> u8 {
+		self.parents
+	}
+
+	/// Returns the parent count and the interior [`Junctions`] as a tuple.
+	///
+	/// To be used when pattern matching, for example:
+	///
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location};
+	/// fn get_parachain_id(loc: &Location) -> Option<u32> {
+	///     match loc.unpack() {
+	///         (0, [Parachain(id)]) => Some(*id),
+	///         _ => None
+	///     }
+	/// }
+	/// ```
+	pub fn unpack(&self) -> (u8, &[Junction]) {
+		(self.parents, self.interior.as_slice())
+	}
+
+	/// Returns boolean indicating whether `self` contains only the specified amount of
+	/// parents and no interior junctions.
+	pub const fn contains_parents_only(&self, count: u8) -> bool {
+		matches!(self.interior, Junctions::Here) && self.parents == count
+	}
+
+	/// Returns the number of parents and junctions in `self`.
+	pub fn len(&self) -> usize {
+		self.parent_count() as usize + self.interior.len()
+	}
+
+	/// Returns the first interior junction, or `None` if the location is empty or contains only
+	/// parents.
+	pub fn first_interior(&self) -> Option<&Junction> {
+		self.interior.first()
+	}
+
+	/// Returns last junction, or `None` if the location is empty or contains only parents.
+	pub fn last(&self) -> Option<&Junction> {
+		self.interior.last()
+	}
+
+	/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
+	/// and the first element (second item in tuple) or `None` if it was empty.
+	pub fn split_first_interior(self) -> (Location, Option<Junction>) {
+		let Location { parents, interior: junctions } = self;
+		let (suffix, first) = junctions.split_first();
+		let location = Location { parents, interior: suffix };
+		(location, first)
+	}
+
+	/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
+	/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
+	/// contains parents.
+	pub fn split_last_interior(self) -> (Location, Option<Junction>) {
+		let Location { parents, interior: junctions } = self;
+		let (prefix, last) = junctions.split_last();
+		let location = Location { parents, interior: prefix };
+		(location, last)
+	}
+
+	/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
+	/// case of overflow.
+	pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
+		self.interior.push(new)
+	}
+
+	/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
+	/// case of overflow.
+	pub fn push_front_interior(
+		&mut self,
+		new: impl Into<Junction>,
+	) -> result::Result<(), Junction> {
+		self.interior.push_front(new)
+	}
+
+	/// Consumes `self` and returns a `Location` suffixed with `new`, or an `Err` with
+	/// the original value of `self` in case of overflow.
+	pub fn pushed_with_interior(
+		self,
+		new: impl Into<Junction>,
+	) -> result::Result<Self, (Self, Junction)> {
+		match self.interior.pushed_with(new) {
+			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
+			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
+		}
+	}
+
+	/// Consumes `self` and returns a `Location` prefixed with `new`, or an `Err` with the
+	/// original value of `self` in case of overflow.
+	pub fn pushed_front_with_interior(
+		self,
+		new: impl Into<Junction>,
+	) -> result::Result<Self, (Self, Junction)> {
+		match self.interior.pushed_front_with(new) {
+			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
+			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
+		}
+	}
+
+	/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
+	/// does not contain that many elements.
+	pub fn at(&self, i: usize) -> Option<&Junction> {
+		let num_parents = self.parents as usize;
+		if i < num_parents {
+			return None
+		}
+		self.interior.at(i - num_parents)
+	}
+
+	/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
+	/// parent or if it doesn't contain that many elements.
+	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
+		let num_parents = self.parents as usize;
+		if i < num_parents {
+			return None
+		}
+		self.interior.at_mut(i - num_parents)
+	}
+
+	/// Decrements the parent count by 1.
+	pub fn dec_parent(&mut self) {
+		self.parents = self.parents.saturating_sub(1);
+	}
+
+	/// Removes the first interior junction from `self`, returning it
+	/// (or `None` if it was empty or if `self` contains only parents).
+	pub fn take_first_interior(&mut self) -> Option<Junction> {
+		self.interior.take_first()
+	}
+
+	/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
+	/// `self` only contains parents).
+	pub fn take_last(&mut self) -> Option<Junction> {
+		self.interior.take_last()
+	}
+
+	/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
+	/// the junctions of `prefix` and that it has a single `Junction` item following.
+	/// If so, returns a reference to this `Junction` item.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location};
+	/// # fn main() {
+	/// let mut m = Location::new(1, [PalletInstance(3), OnlyChild]);
+	/// assert_eq!(
+	///     m.match_and_split(&Location::new(1, [PalletInstance(3)])),
+	///     Some(&OnlyChild),
+	/// );
+	/// assert_eq!(m.match_and_split(&Location::new(1, Here)), None);
+	/// # }
+	/// ```
+	pub fn match_and_split(&self, prefix: &Location) -> Option<&Junction> {
+		if self.parents != prefix.parents {
+			return None
+		}
+		self.interior.match_and_split(&prefix.interior)
+	}
+
+	pub fn starts_with(&self, prefix: &Location) -> bool {
+		self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
+	}
+
+	/// Mutate `self` so that it is suffixed with `suffix`.
+	///
+	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent};
+	/// # fn main() {
+	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
+	/// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(()));
+	/// assert_eq!(m, Location::new(1, [Parachain(21), PalletInstance(3)]));
+	/// # }
+	/// ```
+	pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
+		let prefix = core::mem::replace(self, suffix.into());
+		match self.prepend_with(prefix) {
+			Ok(()) => Ok(()),
+			Err(prefix) => Err(core::mem::replace(self, prefix)),
+		}
+	}
+
+	/// Consume `self` and return its value suffixed with `suffix`.
+	///
+	/// Returns `Err` with the original value of `self` and `suffix` in case of overflow.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent};
+	/// # fn main() {
+	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
+	/// let r = m.appended_with((Parent, PalletInstance(3))).unwrap();
+	/// assert_eq!(r, Location::new(1, [Parachain(21), PalletInstance(3)]));
+	/// # }
+	/// ```
+	pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
+		match self.append_with(suffix) {
+			Ok(()) => Ok(self),
+			Err(suffix) => Err((self, suffix)),
+		}
+	}
+
+	/// Mutate `self` so that it is prefixed with `prefix`.
+	///
+	/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent};
+	/// # fn main() {
+	/// let mut m: Location = (Parent, Parent, PalletInstance(3)).into();
+	/// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(()));
+	/// assert_eq!(m, Location::new(1, [PalletInstance(3)]));
+	/// # }
+	/// ```
+	pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
+		//     prefix     self (suffix)
+		// P .. P I .. I  p .. p i .. i
+		let mut prefix = prefix.into();
+		let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
+		let final_interior = self.interior.len().saturating_add(prepend_interior);
+		if final_interior > super::junctions::MAX_JUNCTIONS {
+			return Err(prefix)
+		}
+		let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
+		let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
+		if final_parents > 255 {
+			return Err(prefix)
+		}
+
+		// cancel out the final item on the prefix interior for one of the suffix's parents.
+		while self.parents > 0 && prefix.take_last().is_some() {
+			self.dec_parent();
+		}
+
+		// now we have either removed all suffix's parents or prefix interior.
+		// this means we can combine the prefix's and suffix's remaining parents/interior since
+		// we know that with at least one empty, the overall order will be respected:
+		//     prefix     self (suffix)
+		// P .. P   (I)   p .. p i .. i => P + p .. (no I) i
+		//  -- or --
+		// P .. P I .. I    (p)  i .. i => P (no p) .. I + i
+
+		self.parents = self.parents.saturating_add(prefix.parents);
+		for j in prefix.interior.into_iter().rev() {
+			self.push_front_interior(j)
+				.expect("final_interior no greater than MAX_JUNCTIONS; qed");
+		}
+		Ok(())
+	}
+
+	/// Consume `self` and return its value prefixed with `prefix`.
+	///
+	/// Returns `Err` with the original value of `self` and `prefix` in case of overflow.
+	///
+	/// # Example
+	/// ```rust
+	/// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent};
+	/// # fn main() {
+	/// let m: Location = (Parent, Parent, PalletInstance(3)).into();
+	/// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap();
+	/// assert_eq!(r, Location::new(1, [PalletInstance(3)]));
+	/// # }
+	/// ```
+	pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
+		match self.prepend_with(prefix) {
+			Ok(()) => Ok(self),
+			Err(prefix) => Err((self, prefix)),
+		}
+	}
+
+	/// Remove any unneeded parents/junctions in `self` based on the given context it will be
+	/// interpreted in.
+	pub fn simplify(&mut self, context: &Junctions) {
+		if context.len() < self.parents as usize {
+			// Not enough context
+			return
+		}
+		while self.parents > 0 {
+			let maybe = context.at(context.len() - (self.parents as usize));
+			match (self.interior.first(), maybe) {
+				(Some(i), Some(j)) if i == j => {
+					self.interior.take_first();
+					self.parents -= 1;
+				},
+				_ => break,
+			}
+		}
+	}
+
+	/// Return the Location subsection identifying the chain that `self` points to.
+	pub fn chain_location(&self) -> Location {
+		let mut clone = self.clone();
+		// start popping junctions until we reach chain identifier
+		while let Some(j) = clone.last() {
+			if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
+				// return chain subsection
+				return clone
+			} else {
+				(clone, _) = clone.split_last_interior();
+			}
+		}
+		Location::new(clone.parents, Junctions::Here)
+	}
+}
+
+impl Reanchorable for Location {
+	type Error = Self;
+
+	/// Mutate `self` so that it represents the same location from the point of view of `target`.
+	/// The context of `self` is provided as `context`.
+	///
+	/// Does not modify `self` in case of overflow.
+	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
+		// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
+
+		// 1. Use our `context` to figure out how the `target` would address us.
+		let inverted_target = context.invert_target(target)?;
+
+		// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
+		// `target`.
+		self.prepend_with(inverted_target).map_err(|_| ())?;
+
+		// 3. Given that we know some of `target` context, ensure that any parents in `self` are
+		// strictly needed.
+		self.simplify(target.interior());
+
+		Ok(())
+	}
+
+	/// Consume `self` and return a new value representing the same location from the point of view
+	/// of `target`. The context of `self` is provided as `context`.
+	///
+	/// Returns the original `self` in case of overflow.
+	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, Self> {
+		match self.reanchor(target, context) {
+			Ok(()) => Ok(self),
+			Err(()) => Err(self),
+		}
+	}
+}
+
+impl TryFrom<OldLocation> for Option<Location> {
+	type Error = ();
+	fn try_from(value: OldLocation) -> result::Result<Self, Self::Error> {
+		Ok(Some(Location::try_from(value)?))
+	}
+}
+
+impl TryFrom<OldLocation> for Location {
+	type Error = ();
+	fn try_from(x: OldLocation) -> result::Result<Self, ()> {
+		Ok(Location { parents: x.parents, interior: x.interior.try_into()? })
+	}
+}
+
+/// A unit struct which can be converted into a `Location` of `parents` value 1.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Parent;
+impl From<Parent> for Location {
+	fn from(_: Parent) -> Self {
+		Location { parents: 1, interior: Junctions::Here }
+	}
+}
+
+/// A tuple struct which can be converted into a `Location` of `parents` value 1 with the inner
+/// interior.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct ParentThen(pub Junctions);
+impl From<ParentThen> for Location {
+	fn from(ParentThen(interior): ParentThen) -> Self {
+		Location { parents: 1, interior }
+	}
+}
+
+/// A unit struct which can be converted into a `Location` of the inner `parents` value.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Ancestor(pub u8);
+impl From<Ancestor> for Location {
+	fn from(Ancestor(parents): Ancestor) -> Self {
+		Location { parents, interior: Junctions::Here }
+	}
+}
+
+/// A unit struct which can be converted into a `Location` of the inner `parents` value and the
+/// inner interior.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct AncestorThen<Interior>(pub u8, pub Interior);
+impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for Location {
+	fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
+		Location { parents, interior: interior.into() }
+	}
+}
+
+impl From<[u8; 32]> for Location {
+	fn from(bytes: [u8; 32]) -> Self {
+		let junction: Junction = bytes.into();
+		junction.into()
+	}
+}
+
+impl From<sp_runtime::AccountId32> for Location {
+	fn from(id: sp_runtime::AccountId32) -> Self {
+		Junction::AccountId32 { network: None, id: id.into() }.into()
+	}
+}
+
+xcm_procedural::impl_conversion_functions_for_location_v5!();
+
+#[cfg(test)]
+mod tests {
+	use crate::v5::prelude::*;
+	use codec::{Decode, Encode};
+
+	#[test]
+	fn conversion_works() {
+		let x: Location = Parent.into();
+		assert_eq!(x, Location { parents: 1, interior: Here });
+		//		let x: Location = (Parent,).into();
+		//		assert_eq!(x, Location { parents: 1, interior: Here });
+		//		let x: Location = (Parent, Parent).into();
+		//		assert_eq!(x, Location { parents: 2, interior: Here });
+		let x: Location = (Parent, Parent, OnlyChild).into();
+		assert_eq!(x, Location { parents: 2, interior: OnlyChild.into() });
+		let x: Location = OnlyChild.into();
+		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
+		let x: Location = (OnlyChild,).into();
+		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
+	}
+
+	#[test]
+	fn simplify_basic_works() {
+		let mut location: Location =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		let context = [Parachain(1000), PalletInstance(42)].into();
+		let expected = GeneralIndex(69).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+
+		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
+		let context = [PalletInstance(42)].into();
+		let expected = GeneralIndex(69).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+
+		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
+		let context = [Parachain(1000), PalletInstance(42)].into();
+		let expected = GeneralIndex(69).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+
+		let mut location: Location =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		let context = [OnlyChild, Parachain(1000), PalletInstance(42)].into();
+		let expected = GeneralIndex(69).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+	}
+
+	#[test]
+	fn simplify_incompatible_location_fails() {
+		let mut location: Location =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		let context = [Parachain(1000), PalletInstance(42), GeneralIndex(42)].into();
+		let expected =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+
+		let mut location: Location =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		let context = [Parachain(1000)].into();
+		let expected =
+			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
+		location.simplify(&context);
+		assert_eq!(location, expected);
+	}
+
+	#[test]
+	fn reanchor_works() {
+		let mut id: Location = (Parent, Parachain(1000), GeneralIndex(42)).into();
+		let context = Parachain(2000).into();
+		let target = (Parent, Parachain(1000)).into();
+		let expected = GeneralIndex(42).into();
+		id.reanchor(&target, &context).unwrap();
+		assert_eq!(id, expected);
+	}
+
+	#[test]
+	fn encode_and_decode_works() {
+		let m = Location {
+			parents: 1,
+			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
+		};
+		let encoded = m.encode();
+		assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
+		let decoded = Location::decode(&mut &encoded[..]);
+		assert_eq!(decoded, Ok(m));
+	}
+
+	#[test]
+	fn match_and_split_works() {
+		let m = Location {
+			parents: 1,
+			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
+		};
+		assert_eq!(m.match_and_split(&Location { parents: 1, interior: Here }), None);
+		assert_eq!(
+			m.match_and_split(&Location { parents: 1, interior: [Parachain(42)].into() }),
+			Some(&AccountIndex64 { network: None, index: 23 })
+		);
+		assert_eq!(m.match_and_split(&m), None);
+	}
+
+	#[test]
+	fn append_with_works() {
+		let acc = AccountIndex64 { network: None, index: 23 };
+		let mut m = Location { parents: 1, interior: [Parachain(42)].into() };
+		assert_eq!(m.append_with([PalletInstance(3), acc]), Ok(()));
+		assert_eq!(
+			m,
+			Location { parents: 1, interior: [Parachain(42), PalletInstance(3), acc].into() }
+		);
+
+		// cannot append to create overly long location
+		let acc = AccountIndex64 { network: None, index: 23 };
+		let m = Location {
+			parents: 254,
+			interior: [Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild].into(),
+		};
+		let suffix: Location = (PalletInstance(3), acc, OnlyChild, OnlyChild).into();
+		assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
+	}
+
+	#[test]
+	fn prepend_with_works() {
+		let mut m = Location {
+			parents: 1,
+			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
+		};
+		assert_eq!(m.prepend_with(Location { parents: 1, interior: [OnlyChild].into() }), Ok(()));
+		assert_eq!(
+			m,
+			Location {
+				parents: 1,
+				interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into()
+			}
+		);
+
+		// cannot prepend to create overly long location
+		let mut m = Location { parents: 254, interior: [Parachain(42)].into() };
+		let prefix = Location { parents: 2, interior: Here };
+		assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
+
+		let prefix = Location { parents: 1, interior: Here };
+		assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
+		assert_eq!(m, Location { parents: 255, interior: [Parachain(42)].into() });
+	}
+
+	#[test]
+	fn double_ended_ref_iteration_works() {
+		let m: Junctions = [Parachain(1000), Parachain(3), PalletInstance(5)].into();
+		let mut iter = m.iter();
+
+		let first = iter.next().unwrap();
+		assert_eq!(first, &Parachain(1000));
+		let third = iter.next_back().unwrap();
+		assert_eq!(third, &PalletInstance(5));
+		let second = iter.next_back().unwrap();
+		assert_eq!(iter.next(), None);
+		assert_eq!(iter.next_back(), None);
+		assert_eq!(second, &Parachain(3));
+
+		let res = Here
+			.pushed_with(*first)
+			.unwrap()
+			.pushed_with(*second)
+			.unwrap()
+			.pushed_with(*third)
+			.unwrap();
+		assert_eq!(m, res);
+
+		// make sure there's no funny business with the 0 indexing
+		let m = Here;
+		let mut iter = m.iter();
+
+		assert_eq!(iter.next(), None);
+		assert_eq!(iter.next_back(), None);
+	}
+
+	#[test]
+	fn conversion_from_other_types_works() {
+		use crate::v4;
+
+		fn takes_location<Arg: Into<Location>>(_arg: Arg) {}
+
+		takes_location(Parent);
+		takes_location(Here);
+		takes_location([Parachain(42)]);
+		takes_location((Ancestor(255), PalletInstance(8)));
+		takes_location((Ancestor(5), Parachain(1), PalletInstance(3)));
+		takes_location((Ancestor(2), Here));
+		takes_location(AncestorThen(
+			3,
+			[Parachain(43), AccountIndex64 { network: None, index: 155 }],
+		));
+		takes_location((Parent, AccountId32 { network: None, id: [0; 32] }));
+		takes_location((Parent, Here));
+		takes_location(ParentThen([Parachain(75)].into()));
+		takes_location([Parachain(100), PalletInstance(3)]);
+
+		assert_eq!(v4::Location::from(v4::Junctions::Here).try_into(), Ok(Location::here()));
+		assert_eq!(v4::Location::from(v4::Parent).try_into(), Ok(Location::parent()));
+		assert_eq!(
+			v4::Location::from((v4::Parent, v4::Parent, v4::Junction::GeneralIndex(42u128),))
+				.try_into(),
+			Ok(Location { parents: 2, interior: [GeneralIndex(42u128)].into() }),
+		);
+	}
+}
diff --git a/polkadot/xcm/src/v5/mod.rs b/polkadot/xcm/src/v5/mod.rs
new file mode 100644
index 00000000000..d455fa48ada
--- /dev/null
+++ b/polkadot/xcm/src/v5/mod.rs
@@ -0,0 +1,1585 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Version 5 of the Cross-Consensus Message format data structures.
+
+pub use super::v3::GetWeight;
+use super::v4::{
+	Instruction as OldInstruction, PalletInfo as OldPalletInfo,
+	QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
+};
+use crate::DoubleEncoded;
+use alloc::{vec, vec::Vec};
+use bounded_collections::{parameter_types, BoundedVec};
+use codec::{
+	self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
+	MaxEncodedLen,
+};
+use core::{fmt::Debug, result};
+use derivative::Derivative;
+use scale_info::TypeInfo;
+
+mod asset;
+mod junction;
+pub(crate) mod junctions;
+mod location;
+mod traits;
+
+pub use asset::{
+	Asset, AssetFilter, AssetId, AssetInstance, AssetTransferFilter, Assets, Fungibility,
+	WildAsset, WildFungibility, MAX_ITEMS_IN_ASSETS,
+};
+pub use junction::{
+	BodyId, BodyPart, Junction, NetworkId, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH,
+};
+pub use junctions::Junctions;
+pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen};
+pub use traits::{
+	send_xcm, validate_send, Error, ExecuteXcm, Outcome, PreparedMessage, Reanchorable, Result,
+	SendError, SendResult, SendXcm, Weight, XcmHash,
+};
+// These parts of XCM v4 are unchanged in XCM v5, and are re-imported here.
+pub use super::v4::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit};
+
+pub const VERSION: super::Version = 5;
+
+/// An identifier for a query.
+pub type QueryId = u64;
+
+#[derive(Derivative, Default, Encode, TypeInfo)]
+#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
+#[codec(encode_bound())]
+#[codec(decode_bound())]
+#[scale_info(bounds(), skip_type_params(Call))]
+pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
+
+pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
+
+environmental::environmental!(instructions_count: u8);
+
+impl<Call> Decode for Xcm<Call> {
+	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
+		instructions_count::using_once(&mut 0, || {
+			let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
+			instructions_count::with(|count| {
+				*count = count.saturating_add(number_of_instructions as u8);
+				if *count > MAX_INSTRUCTIONS_TO_DECODE {
+					return Err(CodecError::from("Max instructions exceeded"))
+				}
+				Ok(())
+			})
+			.expect("Called in `using` context and thus can not return `None`; qed")?;
+			let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
+			Ok(Self(decoded_instructions))
+		})
+	}
+}
+
+impl<Call> Xcm<Call> {
+	/// Create an empty instance.
+	pub fn new() -> Self {
+		Self(vec![])
+	}
+
+	/// Return `true` if no instructions are held in `self`.
+	pub fn is_empty(&self) -> bool {
+		self.0.is_empty()
+	}
+
+	/// Return the number of instructions held in `self`.
+	pub fn len(&self) -> usize {
+		self.0.len()
+	}
+
+	/// Return a reference to the inner value.
+	pub fn inner(&self) -> &[Instruction<Call>] {
+		&self.0
+	}
+
+	/// Return a mutable reference to the inner value.
+	pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
+		&mut self.0
+	}
+
+	/// Consume and return the inner value.
+	pub fn into_inner(self) -> Vec<Instruction<Call>> {
+		self.0
+	}
+
+	/// Return an iterator over references to the items.
+	pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
+		self.0.iter()
+	}
+
+	/// Return an iterator over mutable references to the items.
+	pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
+		self.0.iter_mut()
+	}
+
+	/// Consume and return an iterator over the items.
+	pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
+		self.0.into_iter()
+	}
+
+	/// Consume and either return `self` if it contains some instructions, or if it's empty, then
+	/// instead return the result of `f`.
+	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
+		if self.0.is_empty() {
+			f()
+		} else {
+			self
+		}
+	}
+
+	/// Return the first instruction, if any.
+	pub fn first(&self) -> Option<&Instruction<Call>> {
+		self.0.first()
+	}
+
+	/// Return the last instruction, if any.
+	pub fn last(&self) -> Option<&Instruction<Call>> {
+		self.0.last()
+	}
+
+	/// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise).
+	pub fn only(&self) -> Option<&Instruction<Call>> {
+		if self.0.len() == 1 {
+			self.0.first()
+		} else {
+			None
+		}
+	}
+
+	/// Return the only instruction, contained in `Self`, iff only one exists (returns `self`
+	/// otherwise).
+	pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
+		if self.0.len() == 1 {
+			self.0.pop().ok_or(self)
+		} else {
+			Err(self)
+		}
+	}
+}
+
+impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
+	fn from(c: Vec<Instruction<Call>>) -> Self {
+		Self(c)
+	}
+}
+
+impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
+	fn from(c: Xcm<Call>) -> Self {
+		c.0
+	}
+}
+
+/// A prelude for importing all types typically used when interacting with XCM messages.
+pub mod prelude {
+	mod contents {
+		pub use super::super::{
+			send_xcm, validate_send, Ancestor, AncestorThen, Asset,
+			AssetFilter::{self, *},
+			AssetId,
+			AssetInstance::{self, *},
+			Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
+			Fungibility::{self, *},
+			Instruction::*,
+			InteriorLocation,
+			Junction::{self, *},
+			Junctions::{self, Here},
+			Location, MaybeErrorCode,
+			NetworkId::{self, *},
+			OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
+			QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult,
+			SendXcm, Weight,
+			WeightLimit::{self, *},
+			WildAsset::{self, *},
+			WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
+			XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
+		};
+	}
+	pub use super::{Instruction, Xcm};
+	pub use contents::*;
+	pub mod opaque {
+		pub use super::{
+			super::opaque::{Instruction, Xcm},
+			contents::*,
+		};
+	}
+}
+
+parameter_types! {
+	pub MaxPalletNameLen: u32 = 48;
+	pub MaxPalletsInfo: u32 = 64;
+}
+
+#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
+pub struct PalletInfo {
+	#[codec(compact)]
+	pub index: u32,
+	pub name: BoundedVec<u8, MaxPalletNameLen>,
+	pub module_name: BoundedVec<u8, MaxPalletNameLen>,
+	#[codec(compact)]
+	pub major: u32,
+	#[codec(compact)]
+	pub minor: u32,
+	#[codec(compact)]
+	pub patch: u32,
+}
+
+impl TryInto<OldPalletInfo> for PalletInfo {
+	type Error = ();
+
+	fn try_into(self) -> result::Result<OldPalletInfo, Self::Error> {
+		OldPalletInfo::new(
+			self.index,
+			self.name.into_inner(),
+			self.module_name.into_inner(),
+			self.major,
+			self.minor,
+			self.patch,
+		)
+		.map_err(|_| ())
+	}
+}
+
+impl PalletInfo {
+	pub fn new(
+		index: u32,
+		name: Vec<u8>,
+		module_name: Vec<u8>,
+		major: u32,
+		minor: u32,
+		patch: u32,
+	) -> result::Result<Self, Error> {
+		let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
+		let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
+
+		Ok(Self { index, name, module_name, major, minor, patch })
+	}
+}
+
+/// Response data to a query.
+#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
+pub enum Response {
+	/// No response. Serves as a neutral default.
+	Null,
+	/// Some assets.
+	Assets(Assets),
+	/// The outcome of an XCM instruction.
+	ExecutionResult(Option<(u32, Error)>),
+	/// An XCM version.
+	Version(super::Version),
+	/// The index, instance name, pallet name and version of some pallets.
+	PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
+	/// The status of a dispatch attempt using `Transact`.
+	DispatchResult(MaybeErrorCode),
+}
+
+impl Default for Response {
+	fn default() -> Self {
+		Self::Null
+	}
+}
+
+impl TryFrom<OldResponse> for Response {
+	type Error = ();
+
+	fn try_from(old: OldResponse) -> result::Result<Self, Self::Error> {
+		use OldResponse::*;
+		Ok(match old {
+			Null => Self::Null,
+			Assets(assets) => Self::Assets(assets.try_into()?),
+			ExecutionResult(result) => Self::ExecutionResult(
+				result
+					.map(|(num, old_error)| (num, old_error.try_into()))
+					.map(|(num, result)| result.map(|inner| (num, inner)))
+					.transpose()?,
+			),
+			Version(version) => Self::Version(version),
+			PalletsInfo(pallet_info) => {
+				let inner = pallet_info
+					.into_iter()
+					.map(TryInto::try_into)
+					.collect::<result::Result<Vec<_>, _>>()?;
+				Self::PalletsInfo(
+					BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
+				)
+			},
+			DispatchResult(maybe_error) => Self::DispatchResult(maybe_error),
+		})
+	}
+}
+
+/// Information regarding the composition of a query response.
+#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
+pub struct QueryResponseInfo {
+	/// The destination to which the query response message should be send.
+	pub destination: Location,
+	/// The `query_id` field of the `QueryResponse` message.
+	#[codec(compact)]
+	pub query_id: QueryId,
+	/// The `max_weight` field of the `QueryResponse` message.
+	pub max_weight: Weight,
+}
+
+impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
+	type Error = ();
+
+	fn try_from(old: OldQueryResponseInfo) -> result::Result<Self, Self::Error> {
+		Ok(Self {
+			destination: old.destination.try_into()?,
+			query_id: old.query_id,
+			max_weight: old.max_weight,
+		})
+	}
+}
+
+/// Contextual data pertaining to a specific list of XCM instructions.
+#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
+pub struct XcmContext {
+	/// The current value of the Origin register of the `XCVM`.
+	pub origin: Option<Location>,
+	/// The identity of the XCM; this may be a hash of its versioned encoding but could also be
+	/// a high-level identity set by an appropriate barrier.
+	pub message_id: XcmHash,
+	/// The current value of the Topic register of the `XCVM`.
+	pub topic: Option<[u8; 32]>,
+}
+
+impl XcmContext {
+	/// Constructor which sets the message ID to the supplied parameter and leaves the origin and
+	/// topic unset.
+	pub fn with_message_id(message_id: XcmHash) -> XcmContext {
+		XcmContext { origin: None, message_id, topic: None }
+	}
+}
+
+/// Cross-Consensus Message: A message from one consensus system to another.
+///
+/// Consensus systems that may send and receive messages include blockchains and smart contracts.
+///
+/// All messages are delivered from a known *origin*, expressed as a `Location`.
+///
+/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the
+/// outer XCM format, known as `VersionedXcm`.
+#[derive(
+	Derivative,
+	Encode,
+	Decode,
+	TypeInfo,
+	xcm_procedural::XcmWeightInfoTrait,
+	xcm_procedural::Builder,
+)]
+#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
+#[codec(encode_bound())]
+#[codec(decode_bound())]
+#[scale_info(bounds(), skip_type_params(Call))]
+pub enum Instruction<Call> {
+	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding
+	/// Register.
+	///
+	/// - `assets`: The asset(s) to be withdrawn into holding.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	#[builder(loads_holding)]
+	WithdrawAsset(Assets),
+
+	/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin`
+	/// system and equivalent derivatives should be placed into the Holding Register.
+	///
+	/// - `assets`: The asset(s) that are minted into holding.
+	///
+	/// Safety: `origin` must be trusted to have received and be storing `assets` such that they
+	/// may later be withdrawn should this system send a corresponding message.
+	///
+	/// Kind: *Trusted Indication*.
+	///
+	/// Errors:
+	#[builder(loads_holding)]
+	ReserveAssetDeposited(Assets),
+
+	/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should
+	/// be created and placed into the Holding Register.
+	///
+	/// - `assets`: The asset(s) that are minted into the Holding Register.
+	///
+	/// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets`
+	/// prior as a consequence of sending this message.
+	///
+	/// Kind: *Trusted Indication*.
+	///
+	/// Errors:
+	#[builder(loads_holding)]
+	ReceiveTeleportedAsset(Assets),
+
+	/// Respond with information that the local system is expecting.
+	///
+	/// - `query_id`: The identifier of the query that resulted in this message being sent.
+	/// - `response`: The message content.
+	/// - `max_weight`: The maximum weight that handling this response should take.
+	/// - `querier`: The location responsible for the initiation of the response, if there is one.
+	///   In general this will tend to be the same location as the receiver of this message. NOTE:
+	///   As usual, this is interpreted from the perspective of the receiving consensus system.
+	///
+	/// Safety: Since this is information only, there are no immediate concerns. However, it should
+	/// be remembered that even if the Origin behaves reasonably, it can always be asked to make
+	/// a response to a third-party chain who may or may not be expecting the response. Therefore
+	/// the `querier` should be checked to match the expected value.
+	///
+	/// Kind: *Information*.
+	///
+	/// Errors:
+	QueryResponse {
+		#[codec(compact)]
+		query_id: QueryId,
+		response: Response,
+		max_weight: Weight,
+		querier: Option<Location>,
+	},
+
+	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
+	/// under the ownership of `beneficiary`.
+	///
+	/// - `assets`: The asset(s) to be withdrawn.
+	/// - `beneficiary`: The new owner for the assets.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	TransferAsset { assets: Assets, beneficiary: Location },
+
+	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
+	/// under the ownership of `dest` within this consensus system (i.e. its sovereign account).
+	///
+	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given
+	/// `xcm`.
+	///
+	/// - `assets`: The asset(s) to be withdrawn.
+	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
+	///   beneficiary for the assets and the notification target for the reserve asset deposit
+	///   message.
+	/// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which
+	///   is sent onwards to `dest`.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> },
+
+	/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed
+	/// by the kind of origin `origin_kind`.
+	///
+	/// The Transact Status Register is set according to the result of dispatching the call.
+	///
+	/// - `origin_kind`: The means of expressing the message origin as a dispatch origin.
+	/// - `call`: The encoded transaction to be applied.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	Transact { origin_kind: OriginKind, call: DoubleEncoded<Call> },
+
+	/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by
+	/// the relay-chain to a para.
+	///
+	/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel
+	///   opening.
+	/// - `max_message_size`: The maximum size of a message proposed by the sender.
+	/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
+	///
+	/// Safety: The message should originate directly from the relay-chain.
+	///
+	/// Kind: *System Notification*
+	HrmpNewChannelOpenRequest {
+		#[codec(compact)]
+		sender: u32,
+		#[codec(compact)]
+		max_message_size: u32,
+		#[codec(compact)]
+		max_capacity: u32,
+	},
+
+	/// A message to notify about that a previously sent open channel request has been accepted by
+	/// the recipient. That means that the channel will be opened during the next relay-chain
+	/// session change. This message is meant to be sent by the relay-chain to a para.
+	///
+	/// Safety: The message should originate directly from the relay-chain.
+	///
+	/// Kind: *System Notification*
+	///
+	/// Errors:
+	HrmpChannelAccepted {
+		// NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp
+		// items; and b) because the field's meaning is not obvious/mentioned from the item name.
+		#[codec(compact)]
+		recipient: u32,
+	},
+
+	/// A message to notify that the other party in an open channel decided to close it. In
+	/// particular, `initiator` is going to close the channel opened from `sender` to the
+	/// `recipient`. The close will be enacted at the next relay-chain session change. This message
+	/// is meant to be sent by the relay-chain to a para.
+	///
+	/// Safety: The message should originate directly from the relay-chain.
+	///
+	/// Kind: *System Notification*
+	///
+	/// Errors:
+	HrmpChannelClosing {
+		#[codec(compact)]
+		initiator: u32,
+		#[codec(compact)]
+		sender: u32,
+		#[codec(compact)]
+		recipient: u32,
+	},
+
+	/// Clear the origin.
+	///
+	/// This may be used by the XCM author to ensure that later instructions cannot command the
+	/// authority of the origin (e.g. if they are being relayed from an untrusted source, as often
+	/// the case with `ReserveAssetDeposited`).
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	ClearOrigin,
+
+	/// Mutate the origin to some interior location.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	DescendOrigin(InteriorLocation),
+
+	/// Immediately report the contents of the Error Register to the given destination via XCM.
+	///
+	/// A `QueryResponse` message of type `ExecutionOutcome` is sent to the described destination.
+	///
+	/// - `response_info`: Information for making the response.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	ReportError(QueryResponseInfo),
+
+	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
+	/// the ownership of `beneficiary` within this consensus system.
+	///
+	/// - `assets`: The asset(s) to remove from holding.
+	/// - `beneficiary`: The new owner for the assets.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	DepositAsset { assets: AssetFilter, beneficiary: Location },
+
+	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
+	/// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign
+	/// account).
+	///
+	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
+	///
+	/// - `assets`: The asset(s) to remove from holding.
+	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
+	///   beneficiary for the assets and the notification target for the reserve asset deposit
+	///   message.
+	/// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is
+	///   sent onwards to `dest`.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
+
+	/// Remove the asset(s) (`want`) from the Holding Register and replace them with alternative
+	/// assets.
+	///
+	/// The minimum amount of assets to be received into the Holding Register for the order not to
+	/// fail may be stated.
+	///
+	/// - `give`: The maximum amount of assets to remove from holding.
+	/// - `want`: The minimum amount of assets which `give` should be exchanged for.
+	/// - `maximal`: If `true`, then prefer to give as much as possible up to the limit of `give`
+	///   and receive accordingly more. If `false`, then prefer to give as little as possible in
+	///   order to receive as little as possible while receiving at least `want`.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool },
+
+	/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a
+	/// reserve location.
+	///
+	/// - `assets`: The asset(s) to remove from holding.
+	/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The
+	///   sovereign account of this consensus system *on the reserve location* will have
+	///   appropriate assets withdrawn and `effects` will be executed on them. There will typically
+	///   be only one valid location on any given asset/chain combination.
+	/// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve
+	///   location*.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> },
+
+	/// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message
+	/// to a `dest` location.
+	///
+	/// - `assets`: The asset(s) to remove from holding.
+	/// - `dest`: A valid location that respects teleports coming from this location.
+	/// - `xcm`: The instructions to execute on the assets once arrived *on the destination
+	///   location*.
+	///
+	/// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for
+	/// all `assets`. If it does not, then the assets may be lost.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
+
+	/// Report to a given destination the contents of the Holding Register.
+	///
+	/// A `QueryResponse` message of type `Assets` is sent to the described destination.
+	///
+	/// - `response_info`: Information for making the response.
+	/// - `assets`: A filter for the assets that should be reported back. The assets reported back
+	///   will be, asset-wise, *the lesser of this value and the holding register*. No wildcards
+	///   will be used when reporting assets back.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter },
+
+	/// Pay for the execution of some XCM `xcm` and `orders` with up to `weight`
+	/// picoseconds of execution time, paying for this with up to `fees` from the Holding Register.
+	///
+	/// - `fees`: The asset(s) to remove from the Holding Register to pay for fees.
+	/// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the
+	///   expected maximum weight of the total XCM to be executed for the
+	///   `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	#[builder(pays_fees)]
+	BuyExecution { fees: Asset, weight_limit: WeightLimit },
+
+	/// Refund any surplus weight previously bought with `BuyExecution`.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	RefundSurplus,
+
+	/// Set the Error Handler Register. This is code that should be called in the case of an error
+	/// happening.
+	///
+	/// An error occurring within execution of this code will _NOT_ result in the error register
+	/// being set, nor will an error handler be called due to it. The error handler and appendix
+	/// may each still be set.
+	///
+	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
+	/// weight however includes only the difference between the previous handler and the new
+	/// handler, which can reasonably be negative, which would result in a surplus.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	SetErrorHandler(Xcm<Call>),
+
+	/// Set the Appendix Register. This is code that should be called after code execution
+	/// (including the error handler if any) is finished. This will be called regardless of whether
+	/// an error occurred.
+	///
+	/// Any error occurring due to execution of this code will result in the error register being
+	/// set, and the error handler (if set) firing.
+	///
+	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
+	/// weight however includes only the difference between the previous appendix and the new
+	/// appendix, which can reasonably be negative, which would result in a surplus.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	SetAppendix(Xcm<Call>),
+
+	/// Clear the Error Register.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	ClearError,
+
+	/// Set asset claimer for all the trapped assets during the execution.
+	///
+	/// - `location`: The claimer of any assets potentially trapped during the execution of current
+	///   XCM. It can be an arbitrary location, not necessarily the caller or origin.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	SetAssetClaimer { location: Location },
+	/// Create some assets which are being held on behalf of the origin.
+	///
+	/// - `assets`: The assets which are to be claimed. This must match exactly with the assets
+	///   claimable by the origin of the ticket.
+	/// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the
+	///   asset.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	#[builder(loads_holding)]
+	ClaimAsset { assets: Assets, ticket: Location },
+
+	/// Always throws an error of type `Trap`.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `Trap`: All circumstances, whose inner value is the same as this item's inner value.
+	Trap(#[codec(compact)] u64),
+
+	/// Ask the destination system to respond with the most recent version of XCM that they
+	/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
+	/// responses when they happen.
+	///
+	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
+	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
+	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
+	///   response may not execute at all.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*
+	SubscribeVersion {
+		#[codec(compact)]
+		query_id: QueryId,
+		max_response_weight: Weight,
+	},
+
+	/// Cancel the effect of a previous `SubscribeVersion` instruction.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*
+	UnsubscribeVersion,
+
+	/// Reduce Holding by up to the given assets.
+	///
+	/// Holding is reduced by as much as possible up to the assets in the parameter. It is not an
+	/// error if the Holding does not contain the assets (to make this an error, use `ExpectAsset`
+	/// prior).
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Infallible*
+	BurnAsset(Assets),
+
+	/// Throw an error if Holding does not contain at least the given assets.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `ExpectationFalse`: If Holding Register does not contain the assets in the parameter.
+	ExpectAsset(Assets),
+
+	/// Ensure that the Origin Register equals some given value and throw an error if not.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `ExpectationFalse`: If Origin Register is not equal to the parameter.
+	ExpectOrigin(Option<Location>),
+
+	/// Ensure that the Error Register equals some given value and throw an error if not.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `ExpectationFalse`: If the value of the Error Register is not equal to the parameter.
+	ExpectError(Option<(u32, Error)>),
+
+	/// Ensure that the Transact Status Register equals some given value and throw an error if
+	/// not.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the
+	///   parameter.
+	ExpectTransactStatus(MaybeErrorCode),
+
+	/// Query the existence of a particular pallet type.
+	///
+	/// - `module_name`: The module name of the pallet to query.
+	/// - `response_info`: Information for making the response.
+	///
+	/// Sends a `QueryResponse` to Origin whose data field `PalletsInfo` containing the information
+	/// of all pallets on the local chain whose name is equal to `name`. This is empty in the case
+	/// that the local chain is not based on Substrate Frame.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*.
+	QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
+
+	/// Ensure that a particular pallet with a particular version exists.
+	///
+	/// - `index: Compact`: The index which identifies the pallet. An error if no pallet exists at
+	///   this index.
+	/// - `name: Vec<u8>`: Name which must be equal to the name of the pallet.
+	/// - `module_name: Vec<u8>`: Module name which must be equal to the name of the module in
+	///   which the pallet exists.
+	/// - `crate_major: Compact`: Version number which must be equal to the major version of the
+	///   crate which implements the pallet.
+	/// - `min_crate_minor: Compact`: Version number which must be at most the minor version of the
+	///   crate which implements the pallet.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `ExpectationFalse`: In case any of the expectations are broken.
+	ExpectPallet {
+		#[codec(compact)]
+		index: u32,
+		name: Vec<u8>,
+		module_name: Vec<u8>,
+		#[codec(compact)]
+		crate_major: u32,
+		#[codec(compact)]
+		min_crate_minor: u32,
+	},
+
+	/// Send a `QueryResponse` message containing the value of the Transact Status Register to some
+	/// destination.
+	///
+	/// - `query_response_info`: The information needed for constructing and sending the
+	///   `QueryResponse` message.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*.
+	ReportTransactStatus(QueryResponseInfo),
+
+	/// Set the Transact Status Register to its default, cleared, value.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Infallible*.
+	ClearTransactStatus,
+
+	/// Set the Origin Register to be some child of the Universal Ancestor.
+	///
+	/// Safety: Should only be usable if the Origin is trusted to represent the Universal Ancestor
+	/// child in general. In general, no Origin should be able to represent the Universal Ancestor
+	/// child which is the root of the local consensus system since it would by extension
+	/// allow it to act as any location within the local consensus.
+	///
+	/// The `Junction` parameter should generally be a `GlobalConsensus` variant since it is only
+	/// these which are children of the Universal Ancestor.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*.
+	UniversalOrigin(Junction),
+
+	/// Send a message on to Non-Local Consensus system.
+	///
+	/// This will tend to utilize some extra-consensus mechanism, the obvious one being a bridge.
+	/// A fee may be charged; this may be determined based on the contents of `xcm`. It will be
+	/// taken from the Holding register.
+	///
+	/// - `network`: The remote consensus system to which the message should be exported.
+	/// - `destination`: The location relative to the remote consensus system to which the message
+	///   should be sent on arrival.
+	/// - `xcm`: The message to be exported.
+	///
+	/// As an example, to export a message for execution on Statemine (parachain #1000 in the
+	/// Kusama network), you would call with `network: NetworkId::Kusama` and
+	/// `destination: [Parachain(1000)].into()`. Alternatively, to export a message for execution
+	/// on Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: *Fallible*.
+	ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> },
+
+	/// Lock the locally held asset and prevent further transfer or withdrawal.
+	///
+	/// This restriction may be removed by the `UnlockAsset` instruction being called with an
+	/// Origin of `unlocker` and a `target` equal to the current `Origin`.
+	///
+	/// If the locking is successful, then a `NoteUnlockable` instruction is sent to `unlocker`.
+	///
+	/// - `asset`: The asset(s) which should be locked.
+	/// - `unlocker`: The value which the Origin must be for a corresponding `UnlockAsset`
+	///   instruction to work.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	LockAsset { asset: Asset, unlocker: Location },
+
+	/// Remove the lock over `asset` on this chain and (if nothing else is preventing it) allow the
+	/// asset to be transferred.
+	///
+	/// - `asset`: The asset to be unlocked.
+	/// - `target`: The owner of the asset on the local chain.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	UnlockAsset { asset: Asset, target: Location },
+
+	/// Asset (`asset`) has been locked on the `origin` system and may not be transferred. It may
+	/// only be unlocked with the receipt of the `UnlockAsset` instruction from this chain.
+	///
+	/// - `asset`: The asset(s) which are now unlockable from this origin.
+	/// - `owner`: The owner of the asset on the chain in which it was locked. This may be a
+	///   location specific to the origin network.
+	///
+	/// Safety: `origin` must be trusted to have locked the corresponding `asset`
+	/// prior as a consequence of sending this message.
+	///
+	/// Kind: *Trusted Indication*.
+	///
+	/// Errors:
+	NoteUnlockable { asset: Asset, owner: Location },
+
+	/// Send an `UnlockAsset` instruction to the `locker` for the given `asset`.
+	///
+	/// This may fail if the local system is making use of the fact that the asset is locked or,
+	/// of course, if there is no record that the asset actually is locked.
+	///
+	/// - `asset`: The asset(s) to be unlocked.
+	/// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which an
+	///   `UnlockAsset` should be sent.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	RequestUnlock { asset: Asset, locker: Location },
+
+	/// Sets the Fees Mode Register.
+	///
+	/// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions are
+	///   withdrawn as needed using the same mechanism as `WithdrawAssets`.
+	///
+	/// Kind: *Command*.
+	///
+	/// Errors:
+	SetFeesMode { jit_withdraw: bool },
+
+	/// Set the Topic Register.
+	///
+	/// The 32-byte array identifier in the parameter is not guaranteed to be
+	/// unique; if such a property is desired, it is up to the code author to
+	/// enforce uniqueness.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	SetTopic([u8; 32]),
+
+	/// Clear the Topic Register.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: None.
+	ClearTopic,
+
+	/// Alter the current Origin to another given origin.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors: If the existing state would not allow such a change.
+	AliasOrigin(Location),
+
+	/// A directive to indicate that the origin expects free execution of the message.
+	///
+	/// At execution time, this instruction just does a check on the Origin register.
+	/// However, at the barrier stage messages starting with this instruction can be disregarded if
+	/// the origin is not acceptable for free execution or the `weight_limit` is `Limited` and
+	/// insufficient.
+	///
+	/// Kind: *Indication*
+	///
+	/// Errors: If the given origin is `Some` and not equal to the current Origin register.
+	UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<Location> },
+
+	/// Pay Fees.
+	///
+	/// Successor to `BuyExecution`.
+	/// Defined in fellowship RFC 105.
+	#[builder(pays_fees)]
+	PayFees { asset: Asset },
+
+	/// Initiates cross-chain transfer as follows:
+	///
+	/// Assets in the holding register are matched using the given list of `AssetTransferFilter`s,
+	/// they are then transferred based on their specified transfer type:
+	///
+	/// - teleport: burn local assets and append a `ReceiveTeleportedAsset` XCM instruction to the
+	///   XCM program to be sent onward to the `destination` location,
+	///
+	/// - reserve deposit: place assets under the ownership of `destination` within this consensus
+	///   system (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction
+	///   to the XCM program to be sent onward to the `destination` location,
+	///
+	/// - reserve withdraw: burn local assets and append a `WithdrawAsset` XCM instruction to the
+	///   XCM program to be sent onward to the `destination` location,
+	///
+	/// The onward XCM is then appended a `ClearOrigin` to allow safe execution of any following
+	/// custom XCM instructions provided in `remote_xcm`.
+	///
+	/// The onward XCM also contains either a `PayFees` or `UnpaidExecution` instruction based
+	/// on the presence of the `remote_fees` parameter (see below).
+	///
+	/// If an XCM program requires going through multiple hops, it can compose this instruction to
+	/// be used at every chain along the path, describing that specific leg of the flow.
+	///
+	/// Parameters:
+	/// - `destination`: The location of the program next hop.
+	/// - `remote_fees`: If set to `Some(asset_xfer_filter)`, the single asset matching
+	///   `asset_xfer_filter` in the holding register will be transferred first in the remote XCM
+	///   program, followed by a `PayFees(fee)`, then rest of transfers follow. This guarantees
+	///   `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom` barrier. If set to
+	///   `None`, a `UnpaidExecution` instruction is appended instead. Please note that these
+	///   assets are **reserved** for fees, they are sent to the fees register rather than holding.
+	///   Best practice is to only add here enough to cover fees, and transfer the rest through the
+	///   `assets` parameter.
+	/// - `preserve_origin`: Specifies whether the original origin should be preserved or cleared,
+	///   using the instructions `AliasOrigin` or `ClearOrigin` respectively.
+	/// - `assets`: List of asset filters matched against existing assets in holding. These are
+	///   transferred over to `destination` using the specified transfer type, and deposited to
+	///   holding on `destination`.
+	/// - `remote_xcm`: Custom instructions that will be executed on the `destination` chain. Note
+	///   that these instructions will be executed after a `ClearOrigin` so their origin will be
+	///   `None`.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	InitiateTransfer {
+		destination: Location,
+		remote_fees: Option<AssetTransferFilter>,
+		preserve_origin: bool,
+		assets: Vec<AssetTransferFilter>,
+		remote_xcm: Xcm<()>,
+	},
+}
+
+impl<Call> Xcm<Call> {
+	pub fn into<C>(self) -> Xcm<C> {
+		Xcm::from(self)
+	}
+	pub fn from<C>(xcm: Xcm<C>) -> Self {
+		Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
+	}
+}
+
+impl<Call> Instruction<Call> {
+	pub fn into<C>(self) -> Instruction<C> {
+		Instruction::from(self)
+	}
+	pub fn from<C>(xcm: Instruction<C>) -> Self {
+		use Instruction::*;
+		match xcm {
+			WithdrawAsset(assets) => WithdrawAsset(assets),
+			ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
+			ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
+			QueryResponse { query_id, response, max_weight, querier } =>
+				QueryResponse { query_id, response, max_weight, querier },
+			TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
+			TransferReserveAsset { assets, dest, xcm } =>
+				TransferReserveAsset { assets, dest, xcm },
+			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
+				HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
+			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
+			HrmpChannelClosing { initiator, sender, recipient } =>
+				HrmpChannelClosing { initiator, sender, recipient },
+			Transact { origin_kind, call } => Transact { origin_kind, call: call.into() },
+			ReportError(response_info) => ReportError(response_info),
+			DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
+			DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
+			ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
+			InitiateReserveWithdraw { assets, reserve, xcm } =>
+				InitiateReserveWithdraw { assets, reserve, xcm },
+			InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
+			ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
+			BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
+			ClearOrigin => ClearOrigin,
+			DescendOrigin(who) => DescendOrigin(who),
+			RefundSurplus => RefundSurplus,
+			SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
+			SetAppendix(xcm) => SetAppendix(xcm.into()),
+			ClearError => ClearError,
+			SetAssetClaimer { location } => SetAssetClaimer { location },
+			ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
+			Trap(code) => Trap(code),
+			SubscribeVersion { query_id, max_response_weight } =>
+				SubscribeVersion { query_id, max_response_weight },
+			UnsubscribeVersion => UnsubscribeVersion,
+			BurnAsset(assets) => BurnAsset(assets),
+			ExpectAsset(assets) => ExpectAsset(assets),
+			ExpectOrigin(origin) => ExpectOrigin(origin),
+			ExpectError(error) => ExpectError(error),
+			ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
+			QueryPallet { module_name, response_info } =>
+				QueryPallet { module_name, response_info },
+			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
+				ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
+			ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
+			ClearTransactStatus => ClearTransactStatus,
+			UniversalOrigin(j) => UniversalOrigin(j),
+			ExportMessage { network, destination, xcm } =>
+				ExportMessage { network, destination, xcm },
+			LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
+			UnlockAsset { asset, target } => UnlockAsset { asset, target },
+			NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
+			RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
+			SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
+			SetTopic(topic) => SetTopic(topic),
+			ClearTopic => ClearTopic,
+			AliasOrigin(location) => AliasOrigin(location),
+			UnpaidExecution { weight_limit, check_origin } =>
+				UnpaidExecution { weight_limit, check_origin },
+			PayFees { asset } => PayFees { asset },
+			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
+				InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm },
+		}
+	}
+}
+
+// TODO: Automate Generation
+impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
+	fn weight(&self) -> Weight {
+		use Instruction::*;
+		match self {
+			WithdrawAsset(assets) => W::withdraw_asset(assets),
+			ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
+			ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
+			QueryResponse { query_id, response, max_weight, querier } =>
+				W::query_response(query_id, response, max_weight, querier),
+			TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
+			TransferReserveAsset { assets, dest, xcm } =>
+				W::transfer_reserve_asset(&assets, dest, xcm),
+			Transact { origin_kind, call } => W::transact(origin_kind, call),
+			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
+				W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
+			HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
+			HrmpChannelClosing { initiator, sender, recipient } =>
+				W::hrmp_channel_closing(initiator, sender, recipient),
+			ClearOrigin => W::clear_origin(),
+			DescendOrigin(who) => W::descend_origin(who),
+			ReportError(response_info) => W::report_error(&response_info),
+			DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
+			DepositReserveAsset { assets, dest, xcm } =>
+				W::deposit_reserve_asset(assets, dest, xcm),
+			ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
+			InitiateReserveWithdraw { assets, reserve, xcm } =>
+				W::initiate_reserve_withdraw(assets, reserve, xcm),
+			InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
+			ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
+			BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
+			RefundSurplus => W::refund_surplus(),
+			SetErrorHandler(xcm) => W::set_error_handler(xcm),
+			SetAppendix(xcm) => W::set_appendix(xcm),
+			ClearError => W::clear_error(),
+			SetAssetClaimer { location } => W::set_asset_claimer(location),
+			ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
+			Trap(code) => W::trap(code),
+			SubscribeVersion { query_id, max_response_weight } =>
+				W::subscribe_version(query_id, max_response_weight),
+			UnsubscribeVersion => W::unsubscribe_version(),
+			BurnAsset(assets) => W::burn_asset(assets),
+			ExpectAsset(assets) => W::expect_asset(assets),
+			ExpectOrigin(origin) => W::expect_origin(origin),
+			ExpectError(error) => W::expect_error(error),
+			ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
+			QueryPallet { module_name, response_info } =>
+				W::query_pallet(module_name, response_info),
+			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
+				W::expect_pallet(index, name, module_name, crate_major, min_crate_minor),
+			ReportTransactStatus(response_info) => W::report_transact_status(response_info),
+			ClearTransactStatus => W::clear_transact_status(),
+			UniversalOrigin(j) => W::universal_origin(j),
+			ExportMessage { network, destination, xcm } =>
+				W::export_message(network, destination, xcm),
+			LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
+			UnlockAsset { asset, target } => W::unlock_asset(asset, target),
+			NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
+			RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
+			SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
+			SetTopic(topic) => W::set_topic(topic),
+			ClearTopic => W::clear_topic(),
+			AliasOrigin(location) => W::alias_origin(location),
+			UnpaidExecution { weight_limit, check_origin } =>
+				W::unpaid_execution(weight_limit, check_origin),
+			PayFees { asset } => W::pay_fees(asset),
+			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
+				W::initiate_transfer(destination, remote_fees, preserve_origin, assets, remote_xcm),
+		}
+	}
+}
+
+pub mod opaque {
+	/// The basic concrete type of `Xcm`, which doesn't make any assumptions about the
+	/// format of a call other than it is pre-encoded.
+	pub type Xcm = super::Xcm<()>;
+
+	/// The basic concrete type of `Instruction`, which doesn't make any assumptions about the
+	/// format of a call other than it is pre-encoded.
+	pub type Instruction = super::Instruction<()>;
+}
+
+// Convert from a v4 XCM to a v5 XCM
+impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
+	type Error = ();
+	fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, Self::Error> {
+		Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
+	}
+}
+
+// Convert from a v4 instruction to a v5 instruction
+impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
+	type Error = ();
+	fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, Self::Error> {
+		use OldInstruction::*;
+		Ok(match old_instruction {
+			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
+			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
+			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
+			QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
+				Self::QueryResponse {
+					query_id,
+					querier: querier.try_into()?,
+					response: response.try_into()?,
+					max_weight,
+				},
+			QueryResponse { query_id, response, max_weight, querier: None } =>
+				Self::QueryResponse {
+					query_id,
+					querier: None,
+					response: response.try_into()?,
+					max_weight,
+				},
+			TransferAsset { assets, beneficiary } => Self::TransferAsset {
+				assets: assets.try_into()?,
+				beneficiary: beneficiary.try_into()?,
+			},
+			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
+				assets: assets.try_into()?,
+				dest: dest.try_into()?,
+				xcm: xcm.try_into()?,
+			},
+			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
+				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
+			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
+			HrmpChannelClosing { initiator, sender, recipient } =>
+				Self::HrmpChannelClosing { initiator, sender, recipient },
+			Transact { origin_kind, require_weight_at_most: _, call } =>
+				Self::Transact { origin_kind, call: call.into() },
+			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
+				query_id: response_info.query_id,
+				destination: response_info.destination.try_into().map_err(|_| ())?,
+				max_weight: response_info.max_weight,
+			}),
+			DepositAsset { assets, beneficiary } => {
+				let beneficiary = beneficiary.try_into()?;
+				let assets = assets.try_into()?;
+				Self::DepositAsset { assets, beneficiary }
+			},
+			DepositReserveAsset { assets, dest, xcm } => {
+				let dest = dest.try_into()?;
+				let xcm = xcm.try_into()?;
+				let assets = assets.try_into()?;
+				Self::DepositReserveAsset { assets, dest, xcm }
+			},
+			ExchangeAsset { give, want, maximal } => {
+				let give = give.try_into()?;
+				let want = want.try_into()?;
+				Self::ExchangeAsset { give, want, maximal }
+			},
+			InitiateReserveWithdraw { assets, reserve, xcm } => {
+				let assets = assets.try_into()?;
+				let reserve = reserve.try_into()?;
+				let xcm = xcm.try_into()?;
+				Self::InitiateReserveWithdraw { assets, reserve, xcm }
+			},
+			InitiateTeleport { assets, dest, xcm } => {
+				let assets = assets.try_into()?;
+				let dest = dest.try_into()?;
+				let xcm = xcm.try_into()?;
+				Self::InitiateTeleport { assets, dest, xcm }
+			},
+			ReportHolding { response_info, assets } => {
+				let response_info = QueryResponseInfo {
+					destination: response_info.destination.try_into().map_err(|_| ())?,
+					query_id: response_info.query_id,
+					max_weight: response_info.max_weight,
+				};
+				Self::ReportHolding { response_info, assets: assets.try_into()? }
+			},
+			BuyExecution { fees, weight_limit } => {
+				let fees = fees.try_into()?;
+				let weight_limit = weight_limit.into();
+				Self::BuyExecution { fees, weight_limit }
+			},
+			ClearOrigin => Self::ClearOrigin,
+			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
+			RefundSurplus => Self::RefundSurplus,
+			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
+			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
+			ClearError => Self::ClearError,
+			ClaimAsset { assets, ticket } => {
+				let assets = assets.try_into()?;
+				let ticket = ticket.try_into()?;
+				Self::ClaimAsset { assets, ticket }
+			},
+			Trap(code) => Self::Trap(code),
+			SubscribeVersion { query_id, max_response_weight } =>
+				Self::SubscribeVersion { query_id, max_response_weight },
+			UnsubscribeVersion => Self::UnsubscribeVersion,
+			BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
+			ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
+			ExpectOrigin(maybe_location) => Self::ExpectOrigin(
+				maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?,
+			),
+			ExpectError(maybe_error) => Self::ExpectError(
+				maybe_error
+					.map(|(num, old_error)| (num, old_error.try_into()))
+					.map(|(num, result)| result.map(|inner| (num, inner)))
+					.transpose()
+					.map_err(|_| ())?,
+			),
+			ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
+			QueryPallet { module_name, response_info } => Self::QueryPallet {
+				module_name,
+				response_info: response_info.try_into().map_err(|_| ())?,
+			},
+			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
+				Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
+			ReportTransactStatus(response_info) =>
+				Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?),
+			ClearTransactStatus => Self::ClearTransactStatus,
+			UniversalOrigin(junction) =>
+				Self::UniversalOrigin(junction.try_into().map_err(|_| ())?),
+			ExportMessage { network, destination, xcm } => Self::ExportMessage {
+				network: network.into(),
+				destination: destination.try_into().map_err(|_| ())?,
+				xcm: xcm.try_into().map_err(|_| ())?,
+			},
+			LockAsset { asset, unlocker } => Self::LockAsset {
+				asset: asset.try_into().map_err(|_| ())?,
+				unlocker: unlocker.try_into().map_err(|_| ())?,
+			},
+			UnlockAsset { asset, target } => Self::UnlockAsset {
+				asset: asset.try_into().map_err(|_| ())?,
+				target: target.try_into().map_err(|_| ())?,
+			},
+			NoteUnlockable { asset, owner } => Self::NoteUnlockable {
+				asset: asset.try_into().map_err(|_| ())?,
+				owner: owner.try_into().map_err(|_| ())?,
+			},
+			RequestUnlock { asset, locker } => Self::RequestUnlock {
+				asset: asset.try_into().map_err(|_| ())?,
+				locker: locker.try_into().map_err(|_| ())?,
+			},
+			SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
+			SetTopic(topic) => Self::SetTopic(topic),
+			ClearTopic => Self::ClearTopic,
+			AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?),
+			UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
+				weight_limit,
+				check_origin: check_origin
+					.map(|location| location.try_into())
+					.transpose()
+					.map_err(|_| ())?,
+			},
+		})
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::{prelude::*, *};
+	use crate::v4::{
+		AssetFilter as OldAssetFilter, Junctions::Here as OldHere, WildAsset as OldWildAsset,
+	};
+
+	#[test]
+	fn basic_roundtrip_works() {
+		let xcm = Xcm::<()>(vec![TransferAsset {
+			assets: (Here, 1u128).into(),
+			beneficiary: Here.into(),
+		}]);
+		let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset {
+			assets: (OldHere, 1u128).into(),
+			beneficiary: OldHere.into(),
+		}]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+	}
+
+	#[test]
+	fn teleport_roundtrip_works() {
+		let xcm = Xcm::<()>(vec![
+			ReceiveTeleportedAsset((Here, 1u128).into()),
+			ClearOrigin,
+			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
+		]);
+		let old_xcm: OldXcm<()> = OldXcm::<()>(vec![
+			OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()),
+			OldInstruction::ClearOrigin,
+			OldInstruction::DepositAsset {
+				assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)),
+				beneficiary: OldHere.into(),
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+	}
+
+	#[test]
+	fn reserve_deposit_roundtrip_works() {
+		let xcm = Xcm::<()>(vec![
+			ReserveAssetDeposited((Here, 1u128).into()),
+			ClearOrigin,
+			BuyExecution {
+				fees: (Here, 1u128).into(),
+				weight_limit: Some(Weight::from_parts(1, 1)).into(),
+			},
+			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
+		]);
+		let old_xcm = OldXcm::<()>(vec![
+			OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()),
+			OldInstruction::ClearOrigin,
+			OldInstruction::BuyExecution {
+				fees: (OldHere, 1u128).into(),
+				weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)),
+			},
+			OldInstruction::DepositAsset {
+				assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)),
+				beneficiary: OldHere.into(),
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+	}
+
+	#[test]
+	fn deposit_asset_roundtrip_works() {
+		let xcm = Xcm::<()>(vec![
+			WithdrawAsset((Here, 1u128).into()),
+			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
+		]);
+		let old_xcm = OldXcm::<()>(vec![
+			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
+			OldInstruction::DepositAsset {
+				assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)),
+				beneficiary: OldHere.into(),
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+	}
+
+	#[test]
+	fn deposit_reserve_asset_roundtrip_works() {
+		let xcm = Xcm::<()>(vec![
+			WithdrawAsset((Here, 1u128).into()),
+			DepositReserveAsset {
+				assets: Wild(AllCounted(1)),
+				dest: Here.into(),
+				xcm: Xcm::<()>(vec![]),
+			},
+		]);
+		let old_xcm = OldXcm::<()>(vec![
+			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
+			OldInstruction::DepositReserveAsset {
+				assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)),
+				dest: OldHere.into(),
+				xcm: OldXcm::<()>(vec![]),
+			},
+		]);
+		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
+		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
+		assert_eq!(new_xcm, xcm);
+	}
+
+	#[test]
+	fn decoding_respects_limit() {
+		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
+		let encoded = max_xcm.encode();
+		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
+
+		let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
+		let encoded = big_xcm.encode();
+		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
+
+		let nested_xcm = Xcm::<()>(vec![
+			DepositReserveAsset {
+				assets: All.into(),
+				dest: Here.into(),
+				xcm: max_xcm,
+			};
+			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
+		]);
+		let encoded = nested_xcm.encode();
+		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
+
+		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
+		let encoded = even_more_nested_xcm.encode();
+		assert_eq!(encoded.len(), 342530);
+		// This should not decode since the limit is 100
+		assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
+		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
+	}
+}
diff --git a/polkadot/xcm/src/v5/traits.rs b/polkadot/xcm/src/v5/traits.rs
new file mode 100644
index 00000000000..1f5041ca8d8
--- /dev/null
+++ b/polkadot/xcm/src/v5/traits.rs
@@ -0,0 +1,525 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Cross-Consensus Message format data structures.
+
+pub use crate::v3::{Error as OldError, SendError, XcmHash};
+use codec::{Decode, Encode};
+use core::result;
+use scale_info::TypeInfo;
+
+pub use sp_weights::Weight;
+
+use super::*;
+
+/// Error codes used in XCM. The first errors codes have explicit indices and are part of the XCM
+/// format. Those trailing are merely part of the XCM implementation; there is no expectation that
+/// they will retain the same index over time.
+#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
+#[scale_info(replace_segment("staging_xcm", "xcm"))]
+#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
+pub enum Error {
+	// Errors that happen due to instructions being executed. These alone are defined in the
+	// XCM specification.
+	/// An arithmetic overflow happened.
+	#[codec(index = 0)]
+	Overflow,
+	/// The instruction is intentionally unsupported.
+	#[codec(index = 1)]
+	Unimplemented,
+	/// Origin Register does not contain a value value for a reserve transfer notification.
+	#[codec(index = 2)]
+	UntrustedReserveLocation,
+	/// Origin Register does not contain a value value for a teleport notification.
+	#[codec(index = 3)]
+	UntrustedTeleportLocation,
+	/// `MultiLocation` value too large to descend further.
+	#[codec(index = 4)]
+	LocationFull,
+	/// `MultiLocation` value ascend more parents than known ancestors of local location.
+	#[codec(index = 5)]
+	LocationNotInvertible,
+	/// The Origin Register does not contain a valid value for instruction.
+	#[codec(index = 6)]
+	BadOrigin,
+	/// The location parameter is not a valid value for the instruction.
+	#[codec(index = 7)]
+	InvalidLocation,
+	/// The given asset is not handled.
+	#[codec(index = 8)]
+	AssetNotFound,
+	/// An asset transaction (like withdraw or deposit) failed (typically due to type conversions).
+	#[codec(index = 9)]
+	FailedToTransactAsset(#[codec(skip)] &'static str),
+	/// An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights.
+	#[codec(index = 10)]
+	NotWithdrawable,
+	/// An asset cannot be deposited under the ownership of a particular location.
+	#[codec(index = 11)]
+	LocationCannotHold,
+	/// Attempt to send a message greater than the maximum supported by the transport protocol.
+	#[codec(index = 12)]
+	ExceedsMaxMessageSize,
+	/// The given message cannot be translated into a format supported by the destination.
+	#[codec(index = 13)]
+	DestinationUnsupported,
+	/// Destination is routable, but there is some issue with the transport mechanism.
+	#[codec(index = 14)]
+	Transport(#[codec(skip)] &'static str),
+	/// Destination is known to be unroutable.
+	#[codec(index = 15)]
+	Unroutable,
+	/// Used by `ClaimAsset` when the given claim could not be recognized/found.
+	#[codec(index = 16)]
+	UnknownClaim,
+	/// Used by `Transact` when the functor cannot be decoded.
+	#[codec(index = 17)]
+	FailedToDecode,
+	/// Used by `Transact` to indicate that the given weight limit could be breached by the
+	/// functor.
+	#[codec(index = 18)]
+	MaxWeightInvalid,
+	/// Used by `BuyExecution` when the Holding Register does not contain payable fees.
+	#[codec(index = 19)]
+	NotHoldingFees,
+	/// Used by `BuyExecution` when the fees declared to purchase weight are insufficient.
+	#[codec(index = 20)]
+	TooExpensive,
+	/// Used by the `Trap` instruction to force an error intentionally. Its code is included.
+	#[codec(index = 21)]
+	Trap(u64),
+	/// Used by `ExpectAsset`, `ExpectError` and `ExpectOrigin` when the expectation was not true.
+	#[codec(index = 22)]
+	ExpectationFalse,
+	/// The provided pallet index was not found.
+	#[codec(index = 23)]
+	PalletNotFound,
+	/// The given pallet's name is different to that expected.
+	#[codec(index = 24)]
+	NameMismatch,
+	/// The given pallet's version has an incompatible version to that expected.
+	#[codec(index = 25)]
+	VersionIncompatible,
+	/// The given operation would lead to an overflow of the Holding Register.
+	#[codec(index = 26)]
+	HoldingWouldOverflow,
+	/// The message was unable to be exported.
+	#[codec(index = 27)]
+	ExportError,
+	/// `MultiLocation` value failed to be reanchored.
+	#[codec(index = 28)]
+	ReanchorFailed,
+	/// No deal is possible under the given constraints.
+	#[codec(index = 29)]
+	NoDeal,
+	/// Fees were required which the origin could not pay.
+	#[codec(index = 30)]
+	FeesNotMet,
+	/// Some other error with locking.
+	#[codec(index = 31)]
+	LockError,
+	/// The state was not in a condition where the operation was valid to make.
+	#[codec(index = 32)]
+	NoPermission,
+	/// The universal location of the local consensus is improper.
+	#[codec(index = 33)]
+	Unanchored,
+	/// An asset cannot be deposited, probably because (too much of) it already exists.
+	#[codec(index = 34)]
+	NotDepositable,
+	/// Too many assets matched the given asset filter.
+	#[codec(index = 35)]
+	TooManyAssets,
+
+	// Errors that happen prior to instructions being executed. These fall outside of the XCM
+	// spec.
+	/// XCM version not able to be handled.
+	UnhandledXcmVersion,
+	/// Execution of the XCM would potentially result in a greater weight used than weight limit.
+	WeightLimitReached(Weight),
+	/// The XCM did not pass the barrier condition for execution.
+	///
+	/// The barrier condition differs on different chains and in different circumstances, but
+	/// generally it means that the conditions surrounding the message were not such that the chain
+	/// considers the message worth spending time executing. Since most chains lift the barrier to
+	/// execution on appropriate payment, presentation of an NFT voucher, or based on the message
+	/// origin, it means that none of those were the case.
+	Barrier,
+	/// The weight of an XCM message is not computable ahead of execution.
+	WeightNotComputable,
+	/// Recursion stack limit reached
+	// TODO(https://github.com/paritytech/polkadot-sdk/issues/6199): This should have a fixed index since
+	// we use it in `FrameTransactionalProcessor` // which is used in instructions.
+	// Or we should create a different error for that.
+	ExceedsStackLimit,
+}
+
+impl TryFrom<OldError> for Error {
+	type Error = ();
+	fn try_from(old_error: OldError) -> result::Result<Error, ()> {
+		use OldError::*;
+		Ok(match old_error {
+			Overflow => Self::Overflow,
+			Unimplemented => Self::Unimplemented,
+			UntrustedReserveLocation => Self::UntrustedReserveLocation,
+			UntrustedTeleportLocation => Self::UntrustedTeleportLocation,
+			LocationFull => Self::LocationFull,
+			LocationNotInvertible => Self::LocationNotInvertible,
+			BadOrigin => Self::BadOrigin,
+			InvalidLocation => Self::InvalidLocation,
+			AssetNotFound => Self::AssetNotFound,
+			FailedToTransactAsset(s) => Self::FailedToTransactAsset(s),
+			NotWithdrawable => Self::NotWithdrawable,
+			LocationCannotHold => Self::LocationCannotHold,
+			ExceedsMaxMessageSize => Self::ExceedsMaxMessageSize,
+			DestinationUnsupported => Self::DestinationUnsupported,
+			Transport(s) => Self::Transport(s),
+			Unroutable => Self::Unroutable,
+			UnknownClaim => Self::UnknownClaim,
+			FailedToDecode => Self::FailedToDecode,
+			MaxWeightInvalid => Self::MaxWeightInvalid,
+			NotHoldingFees => Self::NotHoldingFees,
+			TooExpensive => Self::TooExpensive,
+			Trap(i) => Self::Trap(i),
+			ExpectationFalse => Self::ExpectationFalse,
+			PalletNotFound => Self::PalletNotFound,
+			NameMismatch => Self::NameMismatch,
+			VersionIncompatible => Self::VersionIncompatible,
+			HoldingWouldOverflow => Self::HoldingWouldOverflow,
+			ExportError => Self::ExportError,
+			ReanchorFailed => Self::ReanchorFailed,
+			NoDeal => Self::NoDeal,
+			FeesNotMet => Self::FeesNotMet,
+			LockError => Self::LockError,
+			NoPermission => Self::NoPermission,
+			Unanchored => Self::Unanchored,
+			NotDepositable => Self::NotDepositable,
+			UnhandledXcmVersion => Self::UnhandledXcmVersion,
+			WeightLimitReached(weight) => Self::WeightLimitReached(weight),
+			Barrier => Self::Barrier,
+			WeightNotComputable => Self::WeightNotComputable,
+			ExceedsStackLimit => Self::ExceedsStackLimit,
+		})
+	}
+}
+
+impl MaxEncodedLen for Error {
+	fn max_encoded_len() -> usize {
+		// TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields
+		// marked `codec(skip)`. We can hard-code it with the right answer for now.
+		1
+	}
+}
+
+impl From<SendError> for Error {
+	fn from(e: SendError) -> Self {
+		match e {
+			SendError::NotApplicable | SendError::Unroutable | SendError::MissingArgument =>
+				Error::Unroutable,
+			SendError::Transport(s) => Error::Transport(s),
+			SendError::DestinationUnsupported => Error::DestinationUnsupported,
+			SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize,
+			SendError::Fees => Error::FeesNotMet,
+		}
+	}
+}
+
+pub type Result = result::Result<(), Error>;
+
+/// Outcome of an XCM execution.
+#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
+pub enum Outcome {
+	/// Execution completed successfully; given weight was used.
+	Complete { used: Weight },
+	/// Execution started, but did not complete successfully due to the given error; given weight
+	/// was used.
+	Incomplete { used: Weight, error: Error },
+	/// Execution did not start due to the given error.
+	Error { error: Error },
+}
+
+impl Outcome {
+	pub fn ensure_complete(self) -> Result {
+		match self {
+			Outcome::Complete { .. } => Ok(()),
+			Outcome::Incomplete { error, .. } => Err(error),
+			Outcome::Error { error, .. } => Err(error),
+		}
+	}
+	pub fn ensure_execution(self) -> result::Result<Weight, Error> {
+		match self {
+			Outcome::Complete { used, .. } => Ok(used),
+			Outcome::Incomplete { used, .. } => Ok(used),
+			Outcome::Error { error, .. } => Err(error),
+		}
+	}
+	/// How much weight was used by the XCM execution attempt.
+	pub fn weight_used(&self) -> Weight {
+		match self {
+			Outcome::Complete { used, .. } => *used,
+			Outcome::Incomplete { used, .. } => *used,
+			Outcome::Error { .. } => Weight::zero(),
+		}
+	}
+}
+
+impl From<Error> for Outcome {
+	fn from(error: Error) -> Self {
+		Self::Error { error }
+	}
+}
+
+pub trait PreparedMessage {
+	fn weight_of(&self) -> Weight;
+}
+
+/// Type of XCM message executor.
+pub trait ExecuteXcm<Call> {
+	type Prepared: PreparedMessage;
+	fn prepare(message: Xcm<Call>) -> result::Result<Self::Prepared, Xcm<Call>>;
+	fn execute(
+		origin: impl Into<Location>,
+		pre: Self::Prepared,
+		id: &mut XcmHash,
+		weight_credit: Weight,
+	) -> Outcome;
+	fn prepare_and_execute(
+		origin: impl Into<Location>,
+		message: Xcm<Call>,
+		id: &mut XcmHash,
+		weight_limit: Weight,
+		weight_credit: Weight,
+	) -> Outcome {
+		let pre = match Self::prepare(message) {
+			Ok(x) => x,
+			Err(_) => return Outcome::Error { error: Error::WeightNotComputable },
+		};
+		let xcm_weight = pre.weight_of();
+		if xcm_weight.any_gt(weight_limit) {
+			return Outcome::Error { error: Error::WeightLimitReached(xcm_weight) }
+		}
+		Self::execute(origin, pre, id, weight_credit)
+	}
+
+	/// Deduct some `fees` to the sovereign account of the given `location` and place them as per
+	/// the convention for fees.
+	fn charge_fees(location: impl Into<Location>, fees: Assets) -> Result;
+}
+
+pub enum Weightless {}
+impl PreparedMessage for Weightless {
+	fn weight_of(&self) -> Weight {
+		unreachable!()
+	}
+}
+
+impl<C> ExecuteXcm<C> for () {
+	type Prepared = Weightless;
+	fn prepare(message: Xcm<C>) -> result::Result<Self::Prepared, Xcm<C>> {
+		Err(message)
+	}
+	fn execute(_: impl Into<Location>, _: Self::Prepared, _: &mut XcmHash, _: Weight) -> Outcome {
+		unreachable!()
+	}
+	fn charge_fees(_location: impl Into<Location>, _fees: Assets) -> Result {
+		Err(Error::Unimplemented)
+	}
+}
+
+pub trait Reanchorable: Sized {
+	/// Type to return in case of an error.
+	type Error: Debug;
+
+	/// Mutate `self` so that it represents the same location from the point of view of `target`.
+	/// The context of `self` is provided as `context`.
+	///
+	/// Does not modify `self` in case of overflow.
+	fn reanchor(
+		&mut self,
+		target: &Location,
+		context: &InteriorLocation,
+	) -> core::result::Result<(), ()>;
+
+	/// Consume `self` and return a new value representing the same location from the point of view
+	/// of `target`. The context of `self` is provided as `context`.
+	///
+	/// Returns the original `self` in case of overflow.
+	fn reanchored(
+		self,
+		target: &Location,
+		context: &InteriorLocation,
+	) -> core::result::Result<Self, Self::Error>;
+}
+
+/// Result value when attempting to send an XCM message.
+pub type SendResult<T> = result::Result<(T, Assets), SendError>;
+
+/// Utility for sending an XCM message to a given location.
+///
+/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each
+/// router might return `NotApplicable` to pass the execution to the next sender item. Note that
+/// each `NotApplicable` might alter the destination and the XCM message for to the next router.
+///
+/// # Example
+/// ```rust
+/// # use codec::Encode;
+/// # use staging_xcm::v5::{prelude::*, Weight};
+/// # use staging_xcm::VersionedXcm;
+/// # use std::convert::Infallible;
+///
+/// /// A sender that only passes the message through and does nothing.
+/// struct Sender1;
+/// impl SendXcm for Sender1 {
+///     type Ticket = Infallible;
+///     fn validate(_: &mut Option<Location>, _: &mut Option<Xcm<()>>) -> SendResult<Infallible> {
+///         Err(SendError::NotApplicable)
+///     }
+///     fn deliver(_: Infallible) -> Result<XcmHash, SendError> {
+///         unreachable!()
+///     }
+/// }
+///
+/// /// A sender that accepts a message that has two junctions, otherwise stops the routing.
+/// struct Sender2;
+/// impl SendXcm for Sender2 {
+///     type Ticket = ();
+///     fn validate(destination: &mut Option<Location>, message: &mut Option<Xcm<()>>) -> SendResult<()> {
+///         match destination.as_ref().ok_or(SendError::MissingArgument)?.unpack() {
+///             (0, [j1, j2]) => Ok(((), Assets::new())),
+///             _ => Err(SendError::Unroutable),
+///         }
+///     }
+///     fn deliver(_: ()) -> Result<XcmHash, SendError> {
+///         Ok([0; 32])
+///     }
+/// }
+///
+/// /// A sender that accepts a message from a parent, passing through otherwise.
+/// struct Sender3;
+/// impl SendXcm for Sender3 {
+///     type Ticket = ();
+///     fn validate(destination: &mut Option<Location>, message: &mut Option<Xcm<()>>) -> SendResult<()> {
+///         match destination.as_ref().ok_or(SendError::MissingArgument)?.unpack() {
+///             (1, []) => Ok(((), Assets::new())),
+///             _ => Err(SendError::NotApplicable),
+///         }
+///     }
+///     fn deliver(_: ()) -> Result<XcmHash, SendError> {
+///         Ok([0; 32])
+///     }
+/// }
+///
+/// // A call to send via XCM. We don't really care about this.
+/// # fn main() {
+/// let call: Vec<u8> = ().encode();
+/// let message = Xcm(vec![Instruction::Transact {
+///     origin_kind: OriginKind::Superuser,
+///     call: call.into(),
+/// }]);
+/// let message_hash = message.using_encoded(sp_io::hashing::blake2_256);
+///
+/// // Sender2 will block this.
+/// assert!(send_xcm::<(Sender1, Sender2, Sender3)>(Parent.into(), message.clone()).is_err());
+///
+/// // Sender3 will catch this.
+/// assert!(send_xcm::<(Sender1, Sender3)>(Parent.into(), message.clone()).is_ok());
+/// # }
+/// ```
+pub trait SendXcm {
+	/// Intermediate value which connects the two phases of the send operation.
+	type Ticket;
+
+	/// Check whether the given `_message` is deliverable to the given `_destination` and if so
+	/// determine the cost which will be paid by this chain to do so, returning a `Validated` token
+	/// which can be used to enact delivery.
+	///
+	/// The `destination` and `message` must be `Some` (or else an error will be returned) and they
+	/// may only be consumed if the `Err` is not `NotApplicable`.
+	///
+	/// If it is not a destination which can be reached with this type but possibly could by others,
+	/// then this *MUST* return `NotApplicable`. Any other error will cause the tuple
+	/// implementation to exit early without trying other type fields.
+	fn validate(
+		destination: &mut Option<Location>,
+		message: &mut Option<Xcm<()>>,
+	) -> SendResult<Self::Ticket>;
+
+	/// Actually carry out the delivery operation for a previously validated message sending.
+	fn deliver(ticket: Self::Ticket) -> result::Result<XcmHash, SendError>;
+}
+
+#[impl_trait_for_tuples::impl_for_tuples(30)]
+impl SendXcm for Tuple {
+	for_tuples! { type Ticket = (#( Option<Tuple::Ticket> ),* ); }
+
+	fn validate(
+		destination: &mut Option<Location>,
+		message: &mut Option<Xcm<()>>,
+	) -> SendResult<Self::Ticket> {
+		let mut maybe_cost: Option<Assets> = None;
+		let one_ticket: Self::Ticket = (for_tuples! { #(
+			if maybe_cost.is_some() {
+				None
+			} else {
+				match Tuple::validate(destination, message) {
+					Err(SendError::NotApplicable) => None,
+					Err(e) => { return Err(e) },
+					Ok((v, c)) => {
+						maybe_cost = Some(c);
+						Some(v)
+					},
+				}
+			}
+		),* });
+		if let Some(cost) = maybe_cost {
+			Ok((one_ticket, cost))
+		} else {
+			Err(SendError::NotApplicable)
+		}
+	}
+
+	fn deliver(one_ticket: Self::Ticket) -> result::Result<XcmHash, SendError> {
+		for_tuples!( #(
+			if let Some(validated) = one_ticket.Tuple {
+				return Tuple::deliver(validated);
+			}
+		)* );
+		Err(SendError::Unroutable)
+	}
+}
+
+/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps
+/// both in `Some` before passing them as as mutable references into `T::send_xcm`.
+pub fn validate_send<T: SendXcm>(dest: Location, msg: Xcm<()>) -> SendResult<T::Ticket> {
+	T::validate(&mut Some(dest), &mut Some(msg))
+}
+
+/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps
+/// both in `Some` before passing them as as mutable references into `T::send_xcm`.
+///
+/// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message
+/// could not be sent.
+///
+/// Generally you'll want to validate and get the price first to ensure that the sender can pay it
+/// before actually doing the delivery.
+pub fn send_xcm<T: SendXcm>(
+	dest: Location,
+	msg: Xcm<()>,
+) -> result::Result<(XcmHash, Assets), SendError> {
+	let (ticket, price) = T::validate(&mut Some(dest), &mut Some(msg))?;
+	let hash = T::deliver(ticket)?;
+	Ok((hash, price))
+}
diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs
index c995361ea8a..56a8493ef0a 100644
--- a/polkadot/xcm/xcm-builder/src/barriers.rs
+++ b/polkadot/xcm/xcm-builder/src/barriers.rs
@@ -108,6 +108,7 @@ impl<T: Contains<Location>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T>
 					*weight_limit = Limited(max_weight);
 					Ok(())
 				},
+				PayFees { .. } => Ok(()),
 				_ => Err(ProcessMessageError::Overweight(max_weight)),
 			})?;
 		Ok(())
diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs
index bec3bdcb05a..3d68d8ed16a 100644
--- a/polkadot/xcm/xcm-builder/src/lib.rs
+++ b/polkadot/xcm/xcm-builder/src/lib.rs
@@ -108,7 +108,7 @@ pub use nonfungible_adapter::{
 };
 
 mod origin_aliases;
-pub use origin_aliases::AliasForeignAccountId32;
+pub use origin_aliases::*;
 
 mod origin_conversion;
 pub use origin_conversion::{
diff --git a/polkadot/xcm/xcm-builder/src/origin_aliases.rs b/polkadot/xcm/xcm-builder/src/origin_aliases.rs
index d568adc3127..5bc8f0ca32b 100644
--- a/polkadot/xcm/xcm-builder/src/origin_aliases.rs
+++ b/polkadot/xcm/xcm-builder/src/origin_aliases.rs
@@ -17,7 +17,7 @@
 //! Implementation for `ContainsPair<Location, Location>`.
 
 use core::marker::PhantomData;
-use frame_support::traits::{Contains, ContainsPair};
+use frame_support::traits::{Contains, ContainsPair, Get};
 use xcm::latest::prelude::*;
 
 /// Alias a Foreign `AccountId32` with a local `AccountId32` if the foreign `AccountId32` matches
@@ -38,3 +38,34 @@ impl<Prefix: Contains<Location>> ContainsPair<Location, Location>
 		false
 	}
 }
+
+/// Alias a descendant location of the original origin.
+pub struct AliasChildLocation;
+impl ContainsPair<Location, Location> for AliasChildLocation {
+	fn contains(origin: &Location, target: &Location) -> bool {
+		return target.starts_with(origin)
+	}
+}
+
+/// Alias a location if it passes `Filter` and the original origin is root of `Origin`.
+///
+/// This can be used to allow (trusted) system chains root to alias into other locations.
+/// **Warning**: do not use with untrusted `Origin` chains.
+pub struct AliasOriginRootUsingFilter<Origin, Filter>(PhantomData<(Origin, Filter)>);
+impl<Origin, Filter> ContainsPair<Location, Location> for AliasOriginRootUsingFilter<Origin, Filter>
+where
+	Origin: Get<Location>,
+	Filter: Contains<Location>,
+{
+	fn contains(origin: &Location, target: &Location) -> bool {
+		// check that `origin` is a root location
+		match origin.unpack() {
+			(1, [Parachain(_)]) |
+			(2, [GlobalConsensus(_)]) |
+			(2, [GlobalConsensus(_), Parachain(_)]) => (),
+			_ => return false,
+		};
+		// check that `origin` matches `Origin` and `target` matches `Filter`
+		return Origin::get().eq(origin) && Filter::contains(target)
+	}
+}
diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs
index 2e6f8c5fb56..8dafbf66adf 100644
--- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs
+++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs
@@ -18,7 +18,10 @@
 
 use codec::{Decode, FullCodec, MaxEncodedLen};
 use core::{fmt::Debug, marker::PhantomData};
-use frame_support::traits::{ProcessMessage, ProcessMessageError};
+use frame_support::{
+	dispatch::GetDispatchInfo,
+	traits::{ProcessMessage, ProcessMessageError},
+};
 use scale_info::TypeInfo;
 use sp_weights::{Weight, WeightMeter};
 use xcm::prelude::*;
@@ -32,7 +35,7 @@ pub struct ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>(
 impl<
 		MessageOrigin: Into<Location> + FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug,
 		XcmExecutor: ExecuteXcm<Call>,
-		Call,
+		Call: Decode + GetDispatchInfo,
 	> ProcessMessage for ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>
 {
 	type Origin = MessageOrigin;
@@ -125,7 +128,7 @@ mod tests {
 		traits::{ProcessMessageError, ProcessMessageError::*},
 	};
 	use polkadot_test_runtime::*;
-	use xcm::{v3, v4, VersionedXcm};
+	use xcm::{v3, v4, v5, VersionedXcm};
 
 	const ORIGIN: Junction = Junction::OnlyChild;
 	/// The processor to use for tests.
@@ -137,13 +140,15 @@ mod tests {
 		// ClearOrigin works.
 		assert!(process(v3_xcm(true)).unwrap());
 		assert!(process(v4_xcm(true)).unwrap());
+		assert!(process(v5_xcm(true)).unwrap());
 	}
 
 	#[test]
 	fn process_message_trivial_fails() {
 		// Trap makes it fail.
 		assert!(!process(v3_xcm(false)).unwrap());
-		assert!(!process(v3_xcm(false)).unwrap());
+		assert!(!process(v4_xcm(false)).unwrap());
+		assert!(!process(v5_xcm(false)).unwrap());
 	}
 
 	#[test]
@@ -179,7 +184,7 @@ mod tests {
 
 		type Processor = ProcessXcmMessage<Junction, MockedExecutor, ()>;
 
-		let xcm = VersionedXcm::V4(xcm::latest::Xcm::<()>(vec![
+		let xcm = VersionedXcm::from(xcm::latest::Xcm::<()>(vec![
 			xcm::latest::Instruction::<()>::ClearOrigin,
 		]));
 		assert_err!(
@@ -235,6 +240,15 @@ mod tests {
 		VersionedXcm::V4(v4::Xcm::<RuntimeCall>(vec![instr]))
 	}
 
+	fn v5_xcm(success: bool) -> VersionedXcm<RuntimeCall> {
+		let instr = if success {
+			v5::Instruction::<RuntimeCall>::ClearOrigin
+		} else {
+			v5::Instruction::<RuntimeCall>::Trap(1)
+		};
+		VersionedXcm::V5(v5::Xcm::<RuntimeCall>(vec![instr]))
+	}
+
 	fn process(msg: VersionedXcm<RuntimeCall>) -> Result<bool, ProcessMessageError> {
 		process_raw(msg.encode().as_slice())
 	}
diff --git a/polkadot/xcm/xcm-builder/src/tests/aliases.rs b/polkadot/xcm/xcm-builder/src/tests/aliases.rs
index 89c17b09396..dc8b016a6aa 100644
--- a/polkadot/xcm/xcm-builder/src/tests/aliases.rs
+++ b/polkadot/xcm/xcm-builder/src/tests/aliases.rs
@@ -88,3 +88,164 @@ fn alias_origin_should_work() {
 	);
 	assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) });
 }
+
+#[test]
+fn alias_child_location() {
+	// parents differ
+	assert!(!AliasChildLocation::contains(
+		&Location::new(0, Parachain(1)),
+		&Location::new(1, Parachain(1)),
+	));
+	assert!(!AliasChildLocation::contains(
+		&Location::new(0, Here),
+		&Location::new(1, Parachain(1)),
+	));
+	assert!(!AliasChildLocation::contains(&Location::new(1, Here), &Location::new(2, Here),));
+
+	// interiors differ
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, Parachain(1)),
+		&Location::new(1, OnlyChild),
+	));
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, Parachain(1)),
+		&Location::new(1, Parachain(12)),
+	));
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]),
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]),
+	));
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]),
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]),
+	));
+
+	// child to parent not allowed
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]),
+		&Location::new(1, [Parachain(1)]),
+	));
+	assert!(!AliasChildLocation::contains(
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]),
+		&Location::new(1, Here),
+	));
+
+	// parent to child should work
+	assert!(AliasChildLocation::contains(
+		&Location::new(1, Here),
+		&Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]),
+	));
+	assert!(
+		AliasChildLocation::contains(&Location::new(1, Here), &Location::new(1, Parachain(1)),)
+	);
+	assert!(AliasChildLocation::contains(
+		&Location::new(0, Here),
+		&Location::new(0, PalletInstance(42)),
+	));
+	assert!(AliasChildLocation::contains(
+		&Location::new(2, GlobalConsensus(Kusama)),
+		&Location::new(2, [GlobalConsensus(Kusama), Parachain(42), GeneralIndex(12)]),
+	));
+}
+
+#[test]
+fn alias_trusted_root_location() {
+	const ALICE: [u8; 32] = [111u8; 32];
+	const BOB: [u8; 32] = [222u8; 32];
+	const BOB_ON_ETH: [u8; 20] = [222u8; 20];
+
+	parameter_types! {
+		pub AliceOnAssetHub: Location = Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]);
+		pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]);
+	}
+
+	struct MatchSiblingAccounts;
+	impl Contains<Location> for MatchSiblingAccounts {
+		fn contains(location: &Location) -> bool {
+			matches!(location.unpack(), (1, [Parachain(_), AccountId32 { .. }]))
+		}
+	}
+
+	struct MatchOtherGlobalConsensus;
+	impl Contains<Location> for MatchOtherGlobalConsensus {
+		fn contains(location: &Location) -> bool {
+			matches!(location.unpack(), (2, [GlobalConsensus(_)]) | (2, [GlobalConsensus(_), _]))
+		}
+	}
+
+	type AliceOnAssetHubAliasesSiblingAccounts =
+		AliasOriginRootUsingFilter<AliceOnAssetHub, MatchSiblingAccounts>;
+	type AssetHubAliasesSiblingAccounts =
+		AliasOriginRootUsingFilter<SystemAssetHubLocation, MatchSiblingAccounts>;
+	type AssetHubAliasesOtherGlobalConsensus =
+		AliasOriginRootUsingFilter<SystemAssetHubLocation, MatchOtherGlobalConsensus>;
+
+	// Fails if origin is not the root of a chain.
+	assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]),
+		&Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]),
+	));
+	assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]),
+		&Location::new(2, [GlobalConsensus(NetworkId::Ethereum { chain_id: 1 })]),
+	));
+	assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]),
+		&Location::new(
+			2,
+			[
+				GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }),
+				AccountKey20 { key: BOB_ON_ETH, network: None }
+			]
+		),
+	));
+	// Fails if origin doesn't match.
+	assert!(!AssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1001)]),
+		&Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]),
+	));
+	assert!(!AssetHubAliasesOtherGlobalConsensus::contains(
+		&Location::new(1, [Parachain(1001)]),
+		&Location::new(
+			2,
+			[
+				GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }),
+				AccountKey20 { key: BOB_ON_ETH, network: None }
+			]
+		),
+	));
+	// Fails if filter doesn't match.
+	assert!(!AssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000)]),
+		&Location::new(2, [GlobalConsensus(NetworkId::Ethereum { chain_id: 1 })]),
+	));
+	assert!(!AssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000)]),
+		&Location::new(
+			2,
+			[
+				GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }),
+				AccountKey20 { key: BOB_ON_ETH, network: None }
+			]
+		),
+	));
+	assert!(!AssetHubAliasesOtherGlobalConsensus::contains(
+		&Location::new(1, [Parachain(1000)]),
+		&Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]),
+	));
+	// Works when origin is a chain that matches Origin and filter also matches.
+	assert!(AssetHubAliasesSiblingAccounts::contains(
+		&Location::new(1, [Parachain(1000)]),
+		&Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]),
+	));
+	assert!(AssetHubAliasesOtherGlobalConsensus::contains(
+		&Location::new(1, [Parachain(1000)]),
+		&Location::new(
+			2,
+			[
+				GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }),
+				AccountKey20 { key: BOB_ON_ETH, network: None }
+			]
+		),
+	));
+}
diff --git a/polkadot/xcm/xcm-builder/src/tests/transacting.rs b/polkadot/xcm/xcm-builder/src/tests/transacting.rs
index a85c8b9986c..8963e7147fd 100644
--- a/polkadot/xcm/xcm-builder/src/tests/transacting.rs
+++ b/polkadot/xcm/xcm-builder/src/tests/transacting.rs
@@ -22,7 +22,6 @@ fn transacting_should_work() {
 
 	let message = Xcm::<TestCall>(vec![Transact {
 		origin_kind: OriginKind::Native,
-		require_weight_at_most: Weight::from_parts(50, 50),
 		call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
 	}]);
 	let mut hash = fake_message_hash(&message);
@@ -43,7 +42,6 @@ fn transacting_should_respect_max_weight_requirement() {
 
 	let message = Xcm::<TestCall>(vec![Transact {
 		origin_kind: OriginKind::Native,
-		require_weight_at_most: Weight::from_parts(40, 40),
 		call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
 	}]);
 	let mut hash = fake_message_hash(&message);
@@ -55,10 +53,7 @@ fn transacting_should_respect_max_weight_requirement() {
 		weight_limit,
 		Weight::zero(),
 	);
-	assert_eq!(
-		r,
-		Outcome::Incomplete { used: Weight::from_parts(50, 50), error: XcmError::MaxWeightInvalid }
-	);
+	assert_eq!(r, Outcome::Complete { used: Weight::from_parts(60, 60) });
 }
 
 #[test]
@@ -67,7 +62,6 @@ fn transacting_should_refund_weight() {
 
 	let message = Xcm::<TestCall>(vec![Transact {
 		origin_kind: OriginKind::Native,
-		require_weight_at_most: Weight::from_parts(50, 50),
 		call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(30, 30)))
 			.encode()
 			.into(),
@@ -98,7 +92,6 @@ fn paid_transacting_should_refund_payment_for_unused_weight() {
 		BuyExecution { fees, weight_limit: Limited(Weight::from_parts(100, 100)) },
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			// call estimated at 50 but only takes 10.
 			call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(10, 10)))
 				.encode()
@@ -130,7 +123,6 @@ fn report_successful_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ReportTransactStatus(QueryResponseInfo {
@@ -166,7 +158,6 @@ fn report_failed_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ReportTransactStatus(QueryResponseInfo {
@@ -202,7 +193,6 @@ fn expect_successful_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ExpectTransactStatus(MaybeErrorCode::Success),
@@ -221,7 +211,6 @@ fn expect_successful_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ExpectTransactStatus(MaybeErrorCode::Success),
@@ -248,7 +237,6 @@ fn expect_failed_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ExpectTransactStatus(vec![2].into()),
@@ -267,7 +255,6 @@ fn expect_failed_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ExpectTransactStatus(vec![2].into()),
@@ -294,7 +281,6 @@ fn clear_transact_status_should_work() {
 	let message = Xcm::<TestCall>(vec![
 		Transact {
 			origin_kind: OriginKind::Native,
-			require_weight_at_most: Weight::from_parts(50, 50),
 			call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
 		},
 		ClearTransactStatus,
diff --git a/polkadot/xcm/xcm-builder/src/weight.rs b/polkadot/xcm/xcm-builder/src/weight.rs
index 7861fdcc2e5..f8c0275d0f5 100644
--- a/polkadot/xcm/xcm-builder/src/weight.rs
+++ b/polkadot/xcm/xcm-builder/src/weight.rs
@@ -43,26 +43,28 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo, M: Get<u32>> WeightBounds<C>
 		let mut instructions_left = M::get();
 		Self::weight_with_limit(message, &mut instructions_left)
 	}
-	fn instr_weight(instruction: &Instruction<C>) -> Result<Weight, ()> {
+	fn instr_weight(instruction: &mut Instruction<C>) -> Result<Weight, ()> {
 		Self::instr_weight_with_limit(instruction, &mut u32::max_value())
 	}
 }
 
 impl<T: Get<Weight>, C: Decode + GetDispatchInfo, M> FixedWeightBounds<T, C, M> {
-	fn weight_with_limit(message: &Xcm<C>, instrs_limit: &mut u32) -> Result<Weight, ()> {
+	fn weight_with_limit(message: &mut Xcm<C>, instrs_limit: &mut u32) -> Result<Weight, ()> {
 		let mut r: Weight = Weight::zero();
 		*instrs_limit = instrs_limit.checked_sub(message.0.len() as u32).ok_or(())?;
-		for m in message.0.iter() {
-			r = r.checked_add(&Self::instr_weight_with_limit(m, instrs_limit)?).ok_or(())?;
+		for instruction in message.0.iter_mut() {
+			r = r
+				.checked_add(&Self::instr_weight_with_limit(instruction, instrs_limit)?)
+				.ok_or(())?;
 		}
 		Ok(r)
 	}
 	fn instr_weight_with_limit(
-		instruction: &Instruction<C>,
+		instruction: &mut Instruction<C>,
 		instrs_limit: &mut u32,
 	) -> Result<Weight, ()> {
 		let instr_weight = match instruction {
-			Transact { require_weight_at_most, .. } => *require_weight_at_most,
+			Transact { ref mut call, .. } => call.ensure_decoded()?.get_dispatch_info().call_weight,
 			SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?,
 			_ => Weight::zero(),
 		};
@@ -83,7 +85,7 @@ where
 		let mut instructions_left = M::get();
 		Self::weight_with_limit(message, &mut instructions_left)
 	}
-	fn instr_weight(instruction: &Instruction<C>) -> Result<Weight, ()> {
+	fn instr_weight(instruction: &mut Instruction<C>) -> Result<Weight, ()> {
 		Self::instr_weight_with_limit(instruction, &mut u32::max_value())
 	}
 }
@@ -95,20 +97,22 @@ where
 	M: Get<u32>,
 	Instruction<C>: xcm::latest::GetWeight<W>,
 {
-	fn weight_with_limit(message: &Xcm<C>, instrs_limit: &mut u32) -> Result<Weight, ()> {
+	fn weight_with_limit(message: &mut Xcm<C>, instrs_limit: &mut u32) -> Result<Weight, ()> {
 		let mut r: Weight = Weight::zero();
 		*instrs_limit = instrs_limit.checked_sub(message.0.len() as u32).ok_or(())?;
-		for m in message.0.iter() {
-			r = r.checked_add(&Self::instr_weight_with_limit(m, instrs_limit)?).ok_or(())?;
+		for instruction in message.0.iter_mut() {
+			r = r
+				.checked_add(&Self::instr_weight_with_limit(instruction, instrs_limit)?)
+				.ok_or(())?;
 		}
 		Ok(r)
 	}
 	fn instr_weight_with_limit(
-		instruction: &Instruction<C>,
+		instruction: &mut Instruction<C>,
 		instrs_limit: &mut u32,
 	) -> Result<Weight, ()> {
 		let instr_weight = match instruction {
-			Transact { require_weight_at_most, .. } => *require_weight_at_most,
+			Transact { ref mut call, .. } => call.ensure_decoded()?.get_dispatch_info().call_weight,
 			SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?,
 			_ => Weight::zero(),
 		};
@@ -227,7 +231,7 @@ impl<
 		log::trace!(target: "xcm::weight", "UsingComponents::buy_weight weight: {:?}, payment: {:?}, context: {:?}", weight, payment, context);
 		let amount = WeightToFee::weight_to_fee(&weight);
 		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-		let required = (AssetId(AssetIdValue::get()), u128_amount).into();
+		let required = Asset { id: AssetId(AssetIdValue::get()), fun: Fungible(u128_amount) };
 		let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?;
 		self.0 = self.0.saturating_add(weight);
 		self.1 = self.1.saturating_add(amount);
diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
index e95473c5407..9b918fd7eee 100644
--- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
+++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs
@@ -17,7 +17,7 @@
 #![cfg(test)]
 
 use codec::Encode;
-use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
+use frame_support::weights::Weight;
 use polkadot_test_client::{
 	BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder,
 	TestClientBuilder, TestClientBuilderExt,
@@ -79,11 +79,7 @@ fn transact_recursion_limit_works() {
 		Xcm(vec![
 			WithdrawAsset((Here, 1_000).into()),
 			BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited },
-			Transact {
-				origin_kind: OriginKind::Native,
-				require_weight_at_most: call.get_dispatch_info().call_weight,
-				call: call.encode().into(),
-			},
+			Transact { origin_kind: OriginKind::Native, call: call.encode().into() },
 		])
 	};
 	let mut call: Option<polkadot_test_runtime::RuntimeCall> = None;
@@ -241,7 +237,7 @@ fn query_response_fires() {
 		assert_eq!(
 			polkadot_test_runtime::Xcm::query(query_id),
 			Some(QueryStatus::Ready {
-				response: VersionedResponse::V4(Response::ExecutionResult(None)),
+				response: VersionedResponse::from(Response::ExecutionResult(None)),
 				at: 2u32.into()
 			}),
 		)
diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs
index e3addfa3e79..a823dc6fec7 100644
--- a/polkadot/xcm/xcm-executor/src/lib.rs
+++ b/polkadot/xcm/xcm-executor/src/lib.rs
@@ -29,7 +29,7 @@ use frame_support::{
 use sp_core::defer;
 use sp_io::hashing::blake2_128;
 use sp_weights::Weight;
-use xcm::latest::prelude::*;
+use xcm::latest::{prelude::*, AssetTransferFilter};
 
 pub mod traits;
 use traits::{
@@ -47,6 +47,9 @@ pub use assets::AssetsInHolding;
 mod config;
 pub use config::Config;
 
+#[cfg(test)]
+mod tests;
+
 /// A struct to specify how fees are being paid.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct FeesMode {
@@ -83,13 +86,17 @@ pub struct XcmExecutor<Config: config::Config> {
 	appendix_weight: Weight,
 	transact_status: MaybeErrorCode,
 	fees_mode: FeesMode,
+	fees: AssetsInHolding,
 	/// Asset provided in last `BuyExecution` instruction (if any) in current XCM program. Same
 	/// asset type will be used for paying any potential delivery fees incurred by the program.
-	asset_used_for_fees: Option<AssetId>,
+	asset_used_in_buy_execution: Option<AssetId>,
+	/// Stores the current message's weight.
+	message_weight: Weight,
+	asset_claimer: Option<Location>,
 	_config: PhantomData<Config>,
 }
 
-#[cfg(feature = "runtime-benchmarks")]
+#[cfg(any(test, feature = "runtime-benchmarks"))]
 impl<Config: config::Config> XcmExecutor<Config> {
 	pub fn holding(&self) -> &AssetsInHolding {
 		&self.holding
@@ -175,12 +182,24 @@ impl<Config: config::Config> XcmExecutor<Config> {
 	pub fn set_fees_mode(&mut self, v: FeesMode) {
 		self.fees_mode = v
 	}
+	pub fn fees(&self) -> &AssetsInHolding {
+		&self.fees
+	}
+	pub fn set_fees(&mut self, value: AssetsInHolding) {
+		self.fees = value;
+	}
 	pub fn topic(&self) -> &Option<[u8; 32]> {
 		&self.context.topic
 	}
 	pub fn set_topic(&mut self, v: Option<[u8; 32]>) {
 		self.context.topic = v;
 	}
+	pub fn asset_claimer(&self) -> Option<Location> {
+		self.asset_claimer.clone()
+	}
+	pub fn set_message_weight(&mut self, weight: Weight) {
+		self.message_weight = weight;
+	}
 }
 
 pub struct WeighedMessage<Call>(Weight, Xcm<Call>);
@@ -249,6 +268,7 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
 		*id = properties.message_id.unwrap_or(*id);
 
 		let mut vm = Self::new(origin, *id);
+		vm.message_weight = xcm_weight;
 
 		while !message.0.is_empty() {
 			let result = vm.process(message);
@@ -322,7 +342,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			appendix_weight: Weight::zero(),
 			transact_status: Default::default(),
 			fees_mode: FeesMode { jit_withdraw: false },
-			asset_used_for_fees: None,
+			fees: AssetsInHolding::new(),
+			asset_used_in_buy_execution: None,
+			message_weight: Weight::zero(),
+			asset_claimer: None,
 			_config: PhantomData,
 		}
 	}
@@ -346,9 +369,12 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				original_origin = ?self.original_origin,
 				"Trapping assets in holding register",
 			);
-			let effective_origin = self.context.origin.as_ref().unwrap_or(&self.original_origin);
-			let trap_weight =
-				Config::AssetTrap::drop_assets(effective_origin, self.holding, &self.context);
+			let claimer = if let Some(asset_claimer) = self.asset_claimer.as_ref() {
+				asset_claimer
+			} else {
+				self.context.origin.as_ref().unwrap_or(&self.original_origin)
+			};
+			let trap_weight = Config::AssetTrap::drop_assets(claimer, self.holding, &self.context);
 			weight_used.saturating_accrue(trap_weight);
 		};
 
@@ -466,6 +492,11 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				self.holding.subsume_assets(w.into());
 			}
 		}
+		// If there are any leftover `fees`, merge them with `holding`.
+		if !self.fees.is_empty() {
+			let leftover_fees = self.fees.saturating_take(Wild(All));
+			self.holding.subsume_assets(leftover_fees);
+		}
 		tracing::trace!(
 			target: "xcm::refund_surplus",
 			total_refunded = ?self.total_refunded,
@@ -490,7 +521,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			Some(fee) => fee,
 			None => return Ok(()), // No delivery fees need to be paid.
 		};
-		// If `BuyExecution` was called, we use that asset for delivery fees as well.
+		// If `BuyExecution` or `PayFees` was called, we use that asset for delivery fees as well.
 		let asset_to_pay_for_fees =
 			self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone());
 		tracing::trace!(target: "xcm::fees", ?asset_to_pay_for_fees);
@@ -505,15 +536,31 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			tracing::trace!(target: "xcm::fees", ?asset_needed_for_fees);
 			asset_to_pay_for_fees.clone().into()
 		} else {
-			let assets_taken_from_holding_to_pay_delivery_fees = self
-				.holding
-				.try_take(asset_to_pay_for_fees.clone().into())
-				.map_err(|e| {
-					tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees, "Failed to take asset_to_pay_for_fees from holding");
-					XcmError::NotHoldingFees
-				})?;
-			tracing::trace!(target: "xcm::fees", ?assets_taken_from_holding_to_pay_delivery_fees);
-			let mut iter = assets_taken_from_holding_to_pay_delivery_fees.fungible_assets_iter();
+			// This condition exists to support `BuyExecution` while the ecosystem
+			// transitions to `PayFees`.
+			let assets_to_pay_delivery_fees: AssetsInHolding = if self.fees.is_empty() {
+				// Means `BuyExecution` was used, we'll find the fees in the `holding` register.
+				self.holding
+					.try_take(asset_to_pay_for_fees.clone().into())
+					.map_err(|e| {
+						tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees,
+							"Holding doesn't hold enough for fees");
+						XcmError::NotHoldingFees
+					})?
+					.into()
+			} else {
+				// Means `PayFees` was used, we'll find the fees in the `fees` register.
+				self.fees
+					.try_take(asset_to_pay_for_fees.clone().into())
+					.map_err(|e| {
+						tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees,
+							"Fees register doesn't hold enough for fees");
+						XcmError::NotHoldingFees
+					})?
+					.into()
+			};
+			tracing::trace!(target: "xcm::fees", ?assets_to_pay_delivery_fees);
+			let mut iter = assets_to_pay_delivery_fees.fungible_assets_iter();
 			let asset = iter.next().ok_or(XcmError::NotHoldingFees)?;
 			asset.into()
 		};
@@ -544,41 +591,45 @@ impl<Config: config::Config> XcmExecutor<Config> {
 		Ok(())
 	}
 
-	/// Calculates the amount of `self.asset_used_for_fees` required to swap for
-	/// `asset_needed_for_fees`.
+	/// Calculates the amount of asset used in `PayFees` or `BuyExecution` that would be
+	/// charged for swapping to `asset_needed_for_fees`.
 	///
 	/// The calculation is done by `Config::AssetExchanger`.
-	/// If `self.asset_used_for_fees` is not set, it will just return `asset_needed_for_fees`.
+	/// If neither `PayFees` or `BuyExecution` were not used, or no swap is required,
+	/// it will just return `asset_needed_for_fees`.
 	fn calculate_asset_for_delivery_fees(&self, asset_needed_for_fees: Asset) -> Asset {
-		if let Some(asset_wanted_for_fees) = &self.asset_used_for_fees {
-			if *asset_wanted_for_fees != asset_needed_for_fees.id {
-				match Config::AssetExchanger::quote_exchange_price(
-					&(asset_wanted_for_fees.clone(), Fungible(0)).into(),
-					&asset_needed_for_fees.clone().into(),
-					false, // Minimal.
-				) {
-					Some(necessary_assets) =>
-					// We only use the first asset for fees.
-					// If this is not enough to swap for the fee asset then it will error later down
-					// the line.
-						necessary_assets.get(0).unwrap_or(&asset_needed_for_fees.clone()).clone(),
-					// If we can't convert, then we return the original asset.
-					// It will error later in any case.
-					None => {
-						tracing::trace!(
-							target: "xcm::calculate_asset_for_delivery_fees",
-							?asset_wanted_for_fees,
-							"Could not convert fees",
-						);
-						asset_needed_for_fees.clone()
-					},
-				}
-			} else {
-				asset_needed_for_fees
-			}
-		} else {
+		let Some(asset_wanted_for_fees) =
+			// we try to swap first asset in the fees register (should only ever be one),
+			self.fees.fungible.first_key_value().map(|(id, _)| id).or_else(|| {
+				// or the one used in BuyExecution
+				self.asset_used_in_buy_execution.as_ref()
+			})
+			// if it is different than what we need
+			.filter(|&id| asset_needed_for_fees.id.ne(id))
+		else {
+			// either nothing to swap or we're already holding the right asset
+			return asset_needed_for_fees
+		};
+		Config::AssetExchanger::quote_exchange_price(
+			&(asset_wanted_for_fees.clone(), Fungible(0)).into(),
+			&asset_needed_for_fees.clone().into(),
+			false, // Minimal.
+		)
+		.and_then(|necessary_assets| {
+			// We only use the first asset for fees.
+			// If this is not enough to swap for the fee asset then it will error later down
+			// the line.
+			necessary_assets.into_inner().into_iter().next()
+		})
+		.unwrap_or_else(|| {
+			// If we can't convert, then we return the original asset.
+			// It will error later in any case.
+			tracing::trace!(
+				target: "xcm::calculate_asset_for_delivery_fees",
+				?asset_wanted_for_fees, "Could not convert fees",
+			);
 			asset_needed_for_fees
-		}
+		})
 	}
 
 	/// Calculates what `local_querier` would be from the perspective of `destination`.
@@ -614,6 +665,74 @@ impl<Config: config::Config> XcmExecutor<Config> {
 		self.send(destination, message, fee_reason)
 	}
 
+	fn do_reserve_deposit_assets(
+		assets: AssetsInHolding,
+		dest: &Location,
+		remote_xcm: &mut Vec<Instruction<()>>,
+		context: Option<&XcmContext>,
+	) -> Result<Assets, XcmError> {
+		Self::deposit_assets_with_retry(&assets, dest, context)?;
+		// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
+		// cannot be reanchored, because we have already called `deposit_asset` on
+		// all assets.
+		let reanchored_assets = Self::reanchored(assets, dest, None);
+		remote_xcm.push(ReserveAssetDeposited(reanchored_assets.clone()));
+
+		Ok(reanchored_assets)
+	}
+
+	fn do_reserve_withdraw_assets(
+		assets: AssetsInHolding,
+		failed_bin: &mut AssetsInHolding,
+		reserve: &Location,
+		remote_xcm: &mut Vec<Instruction<()>>,
+	) -> Result<Assets, XcmError> {
+		// Must ensure that we recognise the assets as being managed by the destination.
+		#[cfg(not(any(test, feature = "runtime-benchmarks")))]
+		for asset in assets.assets_iter() {
+			ensure!(
+				Config::IsReserve::contains(&asset, &reserve),
+				XcmError::UntrustedReserveLocation
+			);
+		}
+		// Note that here we are able to place any assets which could not be
+		// reanchored back into Holding.
+		let reanchored_assets = Self::reanchored(assets, reserve, Some(failed_bin));
+		remote_xcm.push(WithdrawAsset(reanchored_assets.clone()));
+
+		Ok(reanchored_assets)
+	}
+
+	fn do_teleport_assets(
+		assets: AssetsInHolding,
+		dest: &Location,
+		remote_xcm: &mut Vec<Instruction<()>>,
+		context: &XcmContext,
+	) -> Result<Assets, XcmError> {
+		for asset in assets.assets_iter() {
+			// Must ensure that we have teleport trust with destination for these assets.
+			#[cfg(not(any(test, feature = "runtime-benchmarks")))]
+			ensure!(
+				Config::IsTeleporter::contains(&asset, &dest),
+				XcmError::UntrustedTeleportLocation
+			);
+			// We should check that the asset can actually be teleported out (for
+			// this to be in error, there would need to be an accounting violation
+			// by ourselves, so it's unlikely, but we don't want to allow that kind
+			// of bug to leak into a trusted chain.
+			Config::AssetTransactor::can_check_out(dest, &asset, context)?;
+		}
+		for asset in assets.assets_iter() {
+			Config::AssetTransactor::check_out(dest, &asset, context);
+		}
+		// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
+		// cannot be reanchored, because we have already checked all assets out.
+		let reanchored_assets = Self::reanchored(assets, dest, None);
+		remote_xcm.push(ReceiveTeleportedAsset(reanchored_assets.clone()));
+
+		Ok(reanchored_assets)
+	}
+
 	fn try_reanchor<T: Reanchorable>(
 		reanchorable: T,
 		destination: &Location,
@@ -638,11 +757,16 @@ impl<Config: config::Config> XcmExecutor<Config> {
 		assets.into_assets_iter().collect::<Vec<_>>().into()
 	}
 
-	#[cfg(feature = "runtime-benchmarks")]
+	#[cfg(any(test, feature = "runtime-benchmarks"))]
 	pub fn bench_process(&mut self, xcm: Xcm<Config::RuntimeCall>) -> Result<(), ExecutorError> {
 		self.process(xcm)
 	}
 
+	#[cfg(any(test, feature = "runtime-benchmarks"))]
+	pub fn bench_post_process(self, xcm_weight: Weight) -> Outcome {
+		self.post_process(xcm_weight)
+	}
+
 	fn process(&mut self, xcm: Xcm<Config::RuntimeCall>) -> Result<(), ExecutorError> {
 		tracing::trace!(
 			target: "xcm::process",
@@ -652,7 +776,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			error_handler_weight = ?self.error_handler_weight,
 		);
 		let mut result = Ok(());
-		for (i, instr) in xcm.0.into_iter().enumerate() {
+		for (i, mut instr) in xcm.0.into_iter().enumerate() {
 			match &mut result {
 				r @ Ok(()) => {
 					// Initialize the recursion count only the first time we hit this code in our
@@ -688,7 +812,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 					}
 				},
 				Err(ref mut error) =>
-					if let Ok(x) = Config::Weigher::instr_weight(&instr) {
+					if let Ok(x) = Config::Weigher::instr_weight(&mut instr) {
 						error.weight.saturating_accrue(x)
 					},
 			}
@@ -805,7 +929,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 					Ok(())
 				})
 			},
-			Transact { origin_kind, require_weight_at_most, mut call } => {
+			Transact { origin_kind, mut call } => {
 				// We assume that the Relay-chain is allowed to use transact on this parachain.
 				let origin = self.cloned_origin().ok_or_else(|| {
 					tracing::trace!(
@@ -862,18 +986,6 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				);
 
 				let weight = message_call.get_dispatch_info().call_weight;
-
-				if !weight.all_lte(require_weight_at_most) {
-					tracing::trace!(
-						target: "xcm::process_instruction::transact",
-						%weight,
-						%require_weight_at_most,
-						"Max weight bigger than require at most",
-					);
-
-					return Err(XcmError::MaxWeightInvalid)
-				}
-
 				let maybe_actual_weight =
 					match Config::CallDispatcher::dispatch(message_call, dispatch_origin) {
 						Ok(post_info) => {
@@ -898,9 +1010,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 					};
 				let actual_weight = maybe_actual_weight.unwrap_or(weight);
 				let surplus = weight.saturating_sub(actual_weight);
-				// We assume that the `Config::Weigher` will count the `require_weight_at_most`
-				// for the estimate of how much weight this instruction will take. Now that we know
-				// that it's less, we credit it.
+				// If the actual weight of the call was less than the specified weight, we credit it.
 				//
 				// We make the adjustment for the total surplus, which is used eventually
 				// reported back to the caller and this ensures that they account for the total
@@ -950,7 +1060,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				let old_holding = self.holding.clone();
 				let result = Config::TransactionalProcessor::process(|| {
 					let deposited = self.holding.saturating_take(assets);
-					self.deposit_assets_with_retry(&deposited, &beneficiary)
+					Self::deposit_assets_with_retry(&deposited, &beneficiary, Some(&self.context))
 				});
 				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
 					self.holding = old_holding;
@@ -960,42 +1070,28 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			DepositReserveAsset { assets, dest, xcm } => {
 				let old_holding = self.holding.clone();
 				let result = Config::TransactionalProcessor::process(|| {
-					// we need to do this take/put cycle to solve wildcards and get exact assets to
-					// be weighed
-					let to_weigh = self.holding.saturating_take(assets.clone());
-					self.holding.subsume_assets(to_weigh.clone());
-					let to_weigh_reanchored = Self::reanchored(to_weigh, &dest, None);
-					let mut message_to_weigh =
-						vec![ReserveAssetDeposited(to_weigh_reanchored), ClearOrigin];
-					message_to_weigh.extend(xcm.0.clone().into_iter());
-					let (_, fee) =
-						validate_send::<Config::XcmSender>(dest.clone(), Xcm(message_to_weigh))?;
-					let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| {
-						tracing::trace!(
-							target: "xcm::DepositReserveAsset",
-							"Asset provided to pay for fees {:?}, asset required for delivery fees: {:?}",
-							self.asset_used_for_fees, asset_needed_for_fees,
-						);
-						let asset_to_pay_for_fees =
-							self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone());
-						// set aside fee to be charged by XcmSender
-						let delivery_fee =
-							self.holding.saturating_take(asset_to_pay_for_fees.into());
-						tracing::trace!(target: "xcm::DepositReserveAsset", ?delivery_fee);
-						delivery_fee
-					});
+					let maybe_delivery_fee_from_holding = if self.fees.is_empty() {
+						self.get_delivery_fee_from_holding(&assets, &dest, &xcm)?
+					} else {
+						None
+					};
+
+					let mut message = Vec::with_capacity(xcm.len() + 2);
 					// now take assets to deposit (after having taken delivery fees)
 					let deposited = self.holding.saturating_take(assets);
 					tracing::trace!(target: "xcm::DepositReserveAsset", ?deposited, "Assets except delivery fee");
-					self.deposit_assets_with_retry(&deposited, &dest)?;
-					// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
-					// cannot be reanchored  because we have already called `deposit_asset` on all
-					// assets.
-					let assets = Self::reanchored(deposited, &dest, None);
-					let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
+					Self::do_reserve_deposit_assets(
+						deposited,
+						&dest,
+						&mut message,
+						Some(&self.context),
+					)?;
+					// clear origin for subsequent custom instructions
+					message.push(ClearOrigin);
+					// append custom instructions
 					message.extend(xcm.0.into_iter());
-					// put back delivery_fee in holding register to be charged by XcmSender
-					if let Some(delivery_fee) = maybe_delivery_fee {
+					if let Some(delivery_fee) = maybe_delivery_fee_from_holding {
+						// Put back delivery_fee in holding register to be charged by XcmSender.
 						self.holding.subsume_assets(delivery_fee);
 					}
 					self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?;
@@ -1010,18 +1106,16 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				let old_holding = self.holding.clone();
 				let result = Config::TransactionalProcessor::process(|| {
 					let assets = self.holding.saturating_take(assets);
-					// Must ensure that we recognise the assets as being managed by the destination.
-					#[cfg(not(feature = "runtime-benchmarks"))]
-					for asset in assets.assets_iter() {
-						ensure!(
-							Config::IsReserve::contains(&asset, &reserve),
-							XcmError::UntrustedReserveLocation
-						);
-					}
-					// Note that here we are able to place any assets which could not be reanchored
-					// back into Holding.
-					let assets = Self::reanchored(assets, &reserve, Some(&mut self.holding));
-					let mut message = vec![WithdrawAsset(assets), ClearOrigin];
+					let mut message = Vec::with_capacity(xcm.len() + 2);
+					Self::do_reserve_withdraw_assets(
+						assets,
+						&mut self.holding,
+						&reserve,
+						&mut message,
+					)?;
+					// clear origin for subsequent custom instructions
+					message.push(ClearOrigin);
+					// append custom instructions
 					message.extend(xcm.0.into_iter());
 					self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?;
 					Ok(())
@@ -1033,37 +1127,131 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			},
 			InitiateTeleport { assets, dest, xcm } => {
 				let old_holding = self.holding.clone();
-				let result = (|| -> Result<(), XcmError> {
-					// We must do this first in order to resolve wildcards.
+				let result = Config::TransactionalProcessor::process(|| {
 					let assets = self.holding.saturating_take(assets);
-					// Must ensure that we have teleport trust with destination for these assets.
-					#[cfg(not(feature = "runtime-benchmarks"))]
-					for asset in assets.assets_iter() {
-						ensure!(
-							Config::IsTeleporter::contains(&asset, &dest),
-							XcmError::UntrustedTeleportLocation
-						);
-					}
-					for asset in assets.assets_iter() {
-						// We should check that the asset can actually be teleported out (for this
-						// to be in error, there would need to be an accounting violation by
-						// ourselves, so it's unlikely, but we don't want to allow that kind of bug
-						// to leak into a trusted chain.
-						Config::AssetTransactor::can_check_out(&dest, &asset, &self.context)?;
-					}
-					// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
-					// cannot be reanchored  because we have already checked all assets out.
-					let reanchored_assets = Self::reanchored(assets.clone(), &dest, None);
-					let mut message = vec![ReceiveTeleportedAsset(reanchored_assets), ClearOrigin];
+					let mut message = Vec::with_capacity(xcm.len() + 2);
+					Self::do_teleport_assets(assets, &dest, &mut message, &self.context)?;
+					// clear origin for subsequent custom instructions
+					message.push(ClearOrigin);
+					// append custom instructions
 					message.extend(xcm.0.into_iter());
 					self.send(dest.clone(), Xcm(message), FeeReason::InitiateTeleport)?;
+					Ok(())
+				});
+				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
+					self.holding = old_holding;
+				}
+				result
+			},
+			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } => {
+				let old_holding = self.holding.clone();
+				let result = Config::TransactionalProcessor::process(|| {
+					let mut message = Vec::with_capacity(assets.len() + remote_xcm.len() + 2);
+
+					// We need to transfer the fees and buy execution on remote chain _BEFORE_
+					// transferring the other assets. This is required to satisfy the
+					// `MAX_ASSETS_FOR_BUY_EXECUTION` limit in the `AllowTopLevelPaidExecutionFrom`
+					// barrier.
+					if let Some(remote_fees) = remote_fees {
+						let reanchored_fees = match remote_fees {
+							AssetTransferFilter::Teleport(fees_filter) => {
+								let teleport_fees = self
+									.holding
+									.try_take(fees_filter)
+									.map_err(|_| XcmError::NotHoldingFees)?;
+								Self::do_teleport_assets(
+									teleport_fees,
+									&destination,
+									&mut message,
+									&self.context,
+								)?
+							},
+							AssetTransferFilter::ReserveDeposit(fees_filter) => {
+								let reserve_deposit_fees = self
+									.holding
+									.try_take(fees_filter)
+									.map_err(|_| XcmError::NotHoldingFees)?;
+								Self::do_reserve_deposit_assets(
+									reserve_deposit_fees,
+									&destination,
+									&mut message,
+									Some(&self.context),
+								)?
+							},
+							AssetTransferFilter::ReserveWithdraw(fees_filter) => {
+								let reserve_withdraw_fees = self
+									.holding
+									.try_take(fees_filter)
+									.map_err(|_| XcmError::NotHoldingFees)?;
+								Self::do_reserve_withdraw_assets(
+									reserve_withdraw_fees,
+									&mut self.holding,
+									&destination,
+									&mut message,
+								)?
+							},
+						};
+						ensure!(reanchored_fees.len() == 1, XcmError::TooManyAssets);
+						let fees =
+							reanchored_fees.into_inner().pop().ok_or(XcmError::NotHoldingFees)?;
+						// move these assets to the fees register for covering execution and paying
+						// any subsequent fees
+						message.push(PayFees { asset: fees });
+					} else {
+						// unpaid execution
+						message
+							.push(UnpaidExecution { weight_limit: Unlimited, check_origin: None });
+					}
 
-					for asset in assets.assets_iter() {
-						Config::AssetTransactor::check_out(&dest, &asset, &self.context);
+					// add any extra asset transfers
+					for asset_filter in assets {
+						match asset_filter {
+							AssetTransferFilter::Teleport(assets) => Self::do_teleport_assets(
+								self.holding.saturating_take(assets),
+								&destination,
+								&mut message,
+								&self.context,
+							)?,
+							AssetTransferFilter::ReserveDeposit(assets) =>
+								Self::do_reserve_deposit_assets(
+									self.holding.saturating_take(assets),
+									&destination,
+									&mut message,
+									Some(&self.context),
+								)?,
+							AssetTransferFilter::ReserveWithdraw(assets) =>
+								Self::do_reserve_withdraw_assets(
+									self.holding.saturating_take(assets),
+									&mut self.holding,
+									&destination,
+									&mut message,
+								)?,
+						};
 					}
+					if preserve_origin {
+						// preserve current origin for subsequent user-controlled instructions on
+						// remote chain
+						let original_origin = self
+							.origin_ref()
+							.cloned()
+							.and_then(|origin| {
+								Self::try_reanchor(origin, &destination)
+									.map(|(reanchored, _)| reanchored)
+									.ok()
+							})
+							.ok_or(XcmError::BadOrigin)?;
+						message.push(AliasOrigin(original_origin));
+					} else {
+						// clear origin for subsequent user-controlled instructions on remote chain
+						message.push(ClearOrigin);
+					}
+					// append custom instructions
+					message.extend(remote_xcm.0.into_iter());
+					// send the onward XCM
+					self.send(destination, Xcm(message), FeeReason::InitiateTransfer)?;
 					Ok(())
-				})();
-				if result.is_err() {
+				});
+				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
 					self.holding = old_holding;
 				}
 				result
@@ -1090,24 +1278,61 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				let old_holding = self.holding.clone();
 				// Save the asset being used for execution fees, so we later know what should be
 				// used for delivery fees.
-				self.asset_used_for_fees = Some(fees.id.clone());
-				tracing::trace!(target: "xcm::executor::BuyExecution", asset_used_for_fees = ?self.asset_used_for_fees);
+				self.asset_used_in_buy_execution = Some(fees.id.clone());
+				tracing::trace!(
+					target: "xcm::executor::BuyExecution",
+					asset_used_in_buy_execution = ?self.asset_used_in_buy_execution
+				);
 				// pay for `weight` using up to `fees` of the holding register.
 				let max_fee =
 					self.holding.try_take(fees.clone().into()).map_err(|e| {
-						tracing::error!(target: "xcm::process_instruction::buy_execution", ?e, ?fees, "Failed to take fees from holding");
+						tracing::error!(target: "xcm::process_instruction::buy_execution", ?e, ?fees,
+							"Failed to take fees from holding");
 						XcmError::NotHoldingFees
 					})?;
-				let result = || -> Result<(), XcmError> {
+				let result = Config::TransactionalProcessor::process(|| {
 					let unspent = self.trader.buy_weight(weight, max_fee, &self.context)?;
 					self.holding.subsume_assets(unspent);
 					Ok(())
-				}();
+				});
 				if result.is_err() {
 					self.holding = old_holding;
 				}
 				result
 			},
+			PayFees { asset } => {
+				// Message was not weighed, there is nothing to pay.
+				if self.message_weight == Weight::zero() {
+					tracing::warn!(
+						target: "xcm::executor::PayFees",
+						"Message was not weighed or weight was 0. Nothing will be charged.",
+					);
+					return Ok(());
+				}
+				// Record old holding in case we need to rollback.
+				let old_holding = self.holding.clone();
+				// The max we're willing to pay for fees is decided by the `asset` operand.
+				tracing::trace!(
+					target: "xcm::executor::PayFees",
+					asset_for_fees = ?asset,
+					message_weight = ?self.message_weight,
+				);
+				let max_fee =
+					self.holding.try_take(asset.into()).map_err(|_| XcmError::NotHoldingFees)?;
+				// Pay for execution fees.
+				let result = Config::TransactionalProcessor::process(|| {
+					let unspent =
+						self.trader.buy_weight(self.message_weight, max_fee, &self.context)?;
+					// Move unspent to the `fees` register.
+					self.fees.subsume_assets(unspent);
+					Ok(())
+				});
+				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
+					// Rollback.
+					self.holding = old_holding;
+				}
+				result
+			},
 			RefundSurplus => self.refund_surplus(),
 			SetErrorHandler(mut handler) => {
 				let handler_weight = Config::Weigher::weight(&mut handler)
@@ -1129,6 +1354,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				self.error = None;
 				Ok(())
 			},
+			SetAssetClaimer { location } => {
+				self.asset_claimer = Some(location);
+				Ok(())
+			},
 			ClaimAsset { assets, ticket } => {
 				let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
 				self.ensure_can_subsume_assets(assets.len())?;
@@ -1338,7 +1567,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 			ExchangeAsset { give, want, maximal } => {
 				let old_holding = self.holding.clone();
 				let give = self.holding.saturating_take(give);
-				let result = (|| -> Result<(), XcmError> {
+				let result = Config::TransactionalProcessor::process(|| {
 					self.ensure_can_subsume_assets(want.len())?;
 					let exchange_result = Config::AssetExchanger::exchange_asset(
 						self.origin_ref(),
@@ -1352,7 +1581,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
 					} else {
 						Err(XcmError::NoDeal)
 					}
-				})();
+				});
 				if result.is_err() {
 					self.holding = old_holding;
 				}
@@ -1414,16 +1643,15 @@ impl<Config: config::Config> XcmExecutor<Config> {
 	/// This function can write into storage and also return an error at the same time, it should
 	/// always be called within a transactional context.
 	fn deposit_assets_with_retry(
-		&mut self,
 		to_deposit: &AssetsInHolding,
 		beneficiary: &Location,
+		context: Option<&XcmContext>,
 	) -> Result<(), XcmError> {
 		let mut failed_deposits = Vec::with_capacity(to_deposit.len());
 
 		let mut deposit_result = Ok(());
 		for asset in to_deposit.assets_iter() {
-			deposit_result =
-				Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context));
+			deposit_result = Config::AssetTransactor::deposit_asset(&asset, &beneficiary, context);
 			// if deposit failed for asset, mark it for retry after depositing the others.
 			if deposit_result.is_err() {
 				failed_deposits.push(asset);
@@ -1441,8 +1669,43 @@ impl<Config: config::Config> XcmExecutor<Config> {
 
 		// retry previously failed deposits, this time short-circuiting on any error.
 		for asset in failed_deposits {
-			Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context))?;
+			Config::AssetTransactor::deposit_asset(&asset, &beneficiary, context)?;
 		}
 		Ok(())
 	}
+
+	/// Gets the necessary delivery fee to send a reserve transfer message to `destination` from
+	/// holding.
+	///
+	/// Will be removed once the transition from `BuyExecution` to `PayFees` is complete.
+	fn get_delivery_fee_from_holding(
+		&mut self,
+		assets: &AssetFilter,
+		destination: &Location,
+		xcm: &Xcm<()>,
+	) -> Result<Option<AssetsInHolding>, XcmError> {
+		// we need to do this take/put cycle to solve wildcards and get exact assets to
+		// be weighed
+		let to_weigh = self.holding.saturating_take(assets.clone());
+		self.holding.subsume_assets(to_weigh.clone());
+		let to_weigh_reanchored = Self::reanchored(to_weigh, &destination, None);
+		let mut message_to_weigh = vec![ReserveAssetDeposited(to_weigh_reanchored), ClearOrigin];
+		message_to_weigh.extend(xcm.0.clone().into_iter());
+		let (_, fee) =
+			validate_send::<Config::XcmSender>(destination.clone(), Xcm(message_to_weigh))?;
+		let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| {
+			tracing::trace!(
+				target: "xcm::fees::DepositReserveAsset",
+				"Asset provided to pay for fees {:?}, asset required for delivery fees: {:?}",
+				self.asset_used_in_buy_execution, asset_needed_for_fees,
+			);
+			let asset_to_pay_for_fees =
+				self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone());
+			// set aside fee to be charged by XcmSender
+			let delivery_fee = self.holding.saturating_take(asset_to_pay_for_fees.into());
+			tracing::trace!(target: "xcm::fees::DepositReserveAsset", ?delivery_fee);
+			delivery_fee
+		});
+		Ok(maybe_delivery_fee)
+	}
 }
diff --git a/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs b/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs
new file mode 100644
index 00000000000..09ed1f44cc4
--- /dev/null
+++ b/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs
@@ -0,0 +1,106 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Unit tests related to the `InitiateTransfer` instruction.
+//!
+//! See [Fellowship RFC 100](https://github.com/polkadot-fellows/rfCs/pull/100),
+//! [Fellowship RFC 122](https://github.com/polkadot-fellows/rfCs/pull/122), and the
+//! [specification](https://github.com/polkadot-fellows/xcm-format) for more information.
+
+use xcm::{latest::AssetTransferFilter, prelude::*};
+
+use super::mock::*;
+
+// The sender and recipient we use across these tests.
+const SENDER: [u8; 32] = [0; 32];
+const RECIPIENT: [u8; 32] = [1; 32];
+
+#[test]
+fn clears_origin() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	let xcm_on_dest =
+		Xcm(vec![RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: RECIPIENT.into() }]);
+	let assets: Assets = (Here, 90u128).into();
+	let xcm = Xcm::<TestCall>(vec![
+		WithdrawAsset((Here, 100u128).into()),
+		PayFees { asset: (Here, 10u128).into() },
+		InitiateTransfer {
+			destination: Parent.into(),
+			remote_fees: Some(AssetTransferFilter::ReserveDeposit(assets.into())),
+			preserve_origin: false,
+			assets: vec![],
+			remote_xcm: xcm_on_dest,
+		},
+	]);
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	let res = vm.bench_process(xcm);
+	assert!(res.is_ok(), "execution error {:?}", res);
+
+	let (dest, sent_message) = sent_xcm().pop().unwrap();
+	assert_eq!(dest, Parent.into());
+	assert_eq!(sent_message.len(), 5);
+	let mut instr = sent_message.inner().iter();
+	assert!(matches!(instr.next().unwrap(), ReserveAssetDeposited(..)));
+	assert!(matches!(instr.next().unwrap(), PayFees { .. }));
+	assert!(matches!(instr.next().unwrap(), ClearOrigin));
+	assert!(matches!(instr.next().unwrap(), RefundSurplus));
+	assert!(matches!(instr.next().unwrap(), DepositAsset { .. }));
+}
+
+#[test]
+fn preserves_origin() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	let xcm_on_dest =
+		Xcm(vec![RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: RECIPIENT.into() }]);
+	let assets: Assets = (Here, 90u128).into();
+	let xcm = Xcm::<TestCall>(vec![
+		WithdrawAsset((Here, 100u128).into()),
+		PayFees { asset: (Here, 10u128).into() },
+		InitiateTransfer {
+			destination: Parent.into(),
+			remote_fees: Some(AssetTransferFilter::ReserveDeposit(assets.into())),
+			preserve_origin: true,
+			assets: vec![],
+			remote_xcm: xcm_on_dest,
+		},
+	]);
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	let res = vm.bench_process(xcm);
+	assert!(res.is_ok(), "execution error {:?}", res);
+
+	let (dest, sent_message) = sent_xcm().pop().unwrap();
+	assert_eq!(dest, Parent.into());
+	assert_eq!(sent_message.len(), 5);
+	let mut instr = sent_message.inner().iter();
+	assert!(matches!(instr.next().unwrap(), ReserveAssetDeposited(..)));
+	assert!(matches!(instr.next().unwrap(), PayFees { .. }));
+	assert!(matches!(
+		instr.next().unwrap(),
+		AliasOrigin(origin) if matches!(origin.unpack(), (0, [Parachain(1000), AccountId32 { id: SENDER, network: None }]))
+	));
+	assert!(matches!(instr.next().unwrap(), RefundSurplus));
+	assert!(matches!(instr.next().unwrap(), DepositAsset { .. }));
+}
diff --git a/polkadot/xcm/xcm-executor/src/tests/mock.rs b/polkadot/xcm/xcm-executor/src/tests/mock.rs
new file mode 100644
index 00000000000..9cf258331f3
--- /dev/null
+++ b/polkadot/xcm/xcm-executor/src/tests/mock.rs
@@ -0,0 +1,279 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Mock types and XcmConfig for all executor unit tests.
+
+use alloc::collections::btree_map::BTreeMap;
+use codec::{Decode, Encode};
+use core::cell::RefCell;
+use frame_support::{
+	dispatch::{DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo},
+	parameter_types,
+	traits::{Everything, Nothing, ProcessMessageError},
+	weights::Weight,
+};
+use sp_runtime::traits::Dispatchable;
+use xcm::prelude::*;
+
+use crate::{
+	traits::{DropAssets, Properties, ShouldExecute, TransactAsset, WeightBounds, WeightTrader},
+	AssetsInHolding, Config, XcmExecutor,
+};
+
+/// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we
+/// can inspect its fields.
+pub fn instantiate_executor(
+	origin: impl Into<Location>,
+	message: Xcm<<XcmConfig as Config>::RuntimeCall>,
+) -> (XcmExecutor<XcmConfig>, Weight) {
+	let mut vm =
+		XcmExecutor::<XcmConfig>::new(origin, message.using_encoded(sp_io::hashing::blake2_256));
+	let weight = XcmExecutor::<XcmConfig>::prepare(message.clone()).unwrap().weight_of();
+	vm.message_weight = weight;
+	(vm, weight)
+}
+
+parameter_types! {
+	pub const MaxAssetsIntoHolding: u32 = 10;
+	pub const BaseXcmWeight: Weight = Weight::from_parts(1, 1);
+	pub const MaxInstructions: u32 = 10;
+	pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)].into();
+}
+
+/// Test origin.
+#[derive(Debug)]
+pub struct TestOrigin;
+
+/// Test call.
+///
+/// Doesn't dispatch anything, has an empty implementation of [`Dispatchable`] that
+/// just returns `Ok` with an empty [`PostDispatchInfo`].
+#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone, Copy, scale_info::TypeInfo)]
+pub struct TestCall;
+impl Dispatchable for TestCall {
+	type RuntimeOrigin = TestOrigin;
+	type Config = ();
+	type Info = ();
+	type PostInfo = PostDispatchInfo;
+
+	fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo {
+		Ok(PostDispatchInfo::default())
+	}
+}
+impl GetDispatchInfo for TestCall {
+	fn get_dispatch_info(&self) -> DispatchInfo {
+		DispatchInfo::default()
+	}
+}
+
+/// Test weigher that just returns a fixed weight for every program.
+pub struct TestWeigher;
+impl<C> WeightBounds<C> for TestWeigher {
+	fn weight(_message: &mut Xcm<C>) -> Result<Weight, ()> {
+		Ok(Weight::from_parts(2, 2))
+	}
+
+	fn instr_weight(_instruction: &mut Instruction<C>) -> Result<Weight, ()> {
+		Ok(Weight::from_parts(2, 2))
+	}
+}
+
+thread_local! {
+	pub static ASSETS: RefCell<BTreeMap<Location, AssetsInHolding>> = RefCell::new(BTreeMap::new());
+	pub static SENT_XCM: RefCell<Vec<(Location, Xcm<()>)>> = RefCell::new(Vec::new());
+}
+
+pub fn add_asset(who: impl Into<Location>, what: impl Into<Asset>) {
+	ASSETS.with(|a| {
+		a.borrow_mut()
+			.entry(who.into())
+			.or_insert(AssetsInHolding::new())
+			.subsume(what.into())
+	});
+}
+
+pub fn asset_list(who: impl Into<Location>) -> Vec<Asset> {
+	Assets::from(assets(who)).into_inner()
+}
+
+pub fn assets(who: impl Into<Location>) -> AssetsInHolding {
+	ASSETS.with(|a| a.borrow().get(&who.into()).cloned()).unwrap_or_default()
+}
+
+pub fn get_first_fungible(assets: &AssetsInHolding) -> Option<Asset> {
+	assets.fungible_assets_iter().next()
+}
+
+/// Test asset transactor that withdraws from and deposits to a thread local assets storage.
+pub struct TestAssetTransactor;
+impl TransactAsset for TestAssetTransactor {
+	fn deposit_asset(
+		what: &Asset,
+		who: &Location,
+		_context: Option<&XcmContext>,
+	) -> Result<(), XcmError> {
+		add_asset(who.clone(), what.clone());
+		Ok(())
+	}
+
+	fn withdraw_asset(
+		what: &Asset,
+		who: &Location,
+		_context: Option<&XcmContext>,
+	) -> Result<AssetsInHolding, XcmError> {
+		ASSETS.with(|a| {
+			a.borrow_mut()
+				.get_mut(who)
+				.ok_or(XcmError::NotWithdrawable)?
+				.try_take(what.clone().into())
+				.map_err(|_| XcmError::NotWithdrawable)
+		})
+	}
+}
+
+/// Test barrier that just lets everything through.
+pub struct TestBarrier;
+impl ShouldExecute for TestBarrier {
+	fn should_execute<Call>(
+		_origin: &Location,
+		_instructions: &mut [Instruction<Call>],
+		_max_weight: Weight,
+		_properties: &mut Properties,
+	) -> Result<(), ProcessMessageError> {
+		Ok(())
+	}
+}
+
+/// Test weight to fee that just multiplies `Weight.ref_time` and `Weight.proof_size`.
+pub struct WeightToFee;
+impl WeightToFee {
+	pub fn weight_to_fee(weight: &Weight) -> u128 {
+		weight.ref_time() as u128 * weight.proof_size() as u128
+	}
+}
+
+/// Test weight trader that just buys weight with the native asset (`Here`) and
+/// uses the test `WeightToFee`.
+pub struct TestTrader {
+	weight_bought_so_far: Weight,
+}
+impl WeightTrader for TestTrader {
+	fn new() -> Self {
+		Self { weight_bought_so_far: Weight::zero() }
+	}
+
+	fn buy_weight(
+		&mut self,
+		weight: Weight,
+		payment: AssetsInHolding,
+		_context: &XcmContext,
+	) -> Result<AssetsInHolding, XcmError> {
+		let amount = WeightToFee::weight_to_fee(&weight);
+		let required: Asset = (Here, amount).into();
+		let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?;
+		self.weight_bought_so_far.saturating_add(weight);
+		Ok(unused)
+	}
+
+	fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option<Asset> {
+		let weight = weight.min(self.weight_bought_so_far);
+		let amount = WeightToFee::weight_to_fee(&weight);
+		self.weight_bought_so_far -= weight;
+		if amount > 0 {
+			Some((Here, amount).into())
+		} else {
+			None
+		}
+	}
+}
+
+/// Account where all dropped assets are deposited.
+pub const TRAPPED_ASSETS: [u8; 32] = [255; 32];
+
+/// Test asset trap that moves all dropped assets to the `TRAPPED_ASSETS` account.
+pub struct TestAssetTrap;
+impl DropAssets for TestAssetTrap {
+	fn drop_assets(_origin: &Location, assets: AssetsInHolding, _context: &XcmContext) -> Weight {
+		ASSETS.with(|a| {
+			a.borrow_mut()
+				.entry(TRAPPED_ASSETS.into())
+				.or_insert(AssetsInHolding::new())
+				.subsume_assets(assets)
+		});
+		Weight::zero()
+	}
+}
+
+/// Test sender that always succeeds and puts messages in a dummy queue.
+///
+/// It charges `1` for the delivery fee.
+pub struct TestSender;
+impl SendXcm for TestSender {
+	type Ticket = (Location, Xcm<()>);
+
+	fn validate(
+		destination: &mut Option<Location>,
+		message: &mut Option<Xcm<()>>,
+	) -> SendResult<Self::Ticket> {
+		let ticket = (destination.take().unwrap(), message.take().unwrap());
+		let delivery_fee: Asset = (Here, 1u128).into();
+		Ok((ticket, delivery_fee.into()))
+	}
+
+	fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
+		SENT_XCM.with(|q| q.borrow_mut().push(ticket));
+		Ok([0; 32])
+	}
+}
+
+/// Gets queued test messages.
+pub fn sent_xcm() -> Vec<(Location, Xcm<()>)> {
+	SENT_XCM.with(|q| (*q.borrow()).clone())
+}
+
+/// Test XcmConfig that uses all the test implementations in this file.
+pub struct XcmConfig;
+impl Config for XcmConfig {
+	type RuntimeCall = TestCall;
+	type XcmSender = TestSender;
+	type AssetTransactor = TestAssetTransactor;
+	type OriginConverter = ();
+	type IsReserve = ();
+	type IsTeleporter = ();
+	type UniversalLocation = UniversalLocation;
+	type Barrier = TestBarrier;
+	type Weigher = TestWeigher;
+	type Trader = TestTrader;
+	type ResponseHandler = ();
+	type AssetTrap = TestAssetTrap;
+	type AssetLocker = ();
+	type AssetExchanger = ();
+	type AssetClaims = ();
+	type SubscriptionService = ();
+	type PalletInstancesInfo = ();
+	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
+	type FeeManager = ();
+	type MessageExporter = ();
+	type UniversalAliases = Nothing;
+	type CallDispatcher = Self::RuntimeCall;
+	type SafeCallFilter = Everything;
+	type Aliasers = Nothing;
+	type TransactionalProcessor = ();
+	type HrmpNewChannelOpenRequestHandler = ();
+	type HrmpChannelAcceptedHandler = ();
+	type HrmpChannelClosingHandler = ();
+	type XcmRecorder = ();
+}
diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs b/polkadot/xcm/xcm-executor/src/tests/mod.rs
similarity index 70%
rename from polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs
rename to polkadot/xcm/xcm-executor/src/tests/mod.rs
index 1ed8dd38cba..5c133871f0b 100644
--- a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs
+++ b/polkadot/xcm/xcm-executor/src/tests/mod.rs
@@ -14,16 +14,13 @@
 // You should have received a copy of the GNU General Public License
 // along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
 
-//! Test error when there's no `BuyExecution` instruction.
-
-use xcm_procedural::Builder;
-
-struct Xcm<Call>(pub Vec<Instruction<Call>>);
-
-#[derive(Builder)]
-enum Instruction<Call> {
-    UnpaidExecution { weight_limit: (u32, u32) },
-    Transact { call: Call },
-}
-
-fn main() {}
+//! Unit tests for the XCM executor.
+//!
+//! These exclude any cross-chain functionality. For those, look at the
+//! `xcm-emulator` based tests in the cumulus folder.
+//! These tests deal with internal state changes of the XCVM.
+
+mod initiate_transfer;
+mod mock;
+mod pay_fees;
+mod set_asset_claimer;
diff --git a/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs b/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs
new file mode 100644
index 00000000000..4c196831e6a
--- /dev/null
+++ b/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs
@@ -0,0 +1,257 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Unit tests related to the `fees` register and `PayFees` instruction.
+//!
+//! See [Fellowship RFC 105](https://github.com/polkadot-fellows/rfCs/pull/105)
+//! and the [specification](https://github.com/polkadot-fellows/xcm-format) for more information.
+
+use xcm::prelude::*;
+
+use super::mock::*;
+
+// The sender and recipient we use across these tests.
+const SENDER: [u8; 32] = [0; 32];
+const RECIPIENT: [u8; 32] = [1; 32];
+
+// ===== Happy path =====
+
+// This is a sort of backwards compatibility test.
+// Since `PayFees` is a replacement for `BuyExecution`, we need to make sure it at least
+// manages to do the same thing, paying for execution fees.
+#[test]
+fn works_for_execution_fees() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.deposit_asset(All, RECIPIENT)
+		.build();
+
+	let (mut vm, weight) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// Execution fees were 4, so we still have 6 left in the `fees` register.
+	assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 6u128).into());
+
+	// The recipient received all the assets in the holding register, so `100` that
+	// were withdrawn, minus the `10` that were destinated for fee payment.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]);
+
+	// Leftover fees get trapped.
+	assert!(vm.bench_post_process(weight).ensure_complete().is_ok());
+	assert_eq!(asset_list(TRAPPED_ASSETS), [(Here, 6u128).into()])
+}
+
+// This tests the new functionality provided by `PayFees`, being able to pay for
+// delivery fees from the `fees` register.
+#[test]
+fn works_for_delivery_fees() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Information to send messages.
+	// We don't care about the specifics since we're not actually sending them.
+	let query_response_info =
+		QueryResponseInfo { destination: Parent.into(), query_id: 0, max_weight: Weight::zero() };
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		.pay_fees((Here, 10u128))
+		// Send a bunch of messages, each charging delivery fees.
+		.report_error(query_response_info.clone())
+		.report_error(query_response_info.clone())
+		.report_error(query_response_info)
+		.deposit_asset(All, RECIPIENT)
+		.build();
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// Execution fees were 4, delivery were 3, so we are left with only 3 in the `fees` register.
+	assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 3u128).into());
+
+	// The recipient received all the assets in the holding register, so `100` that
+	// were withdrawn, minus the `10` that were destinated for fee payment.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]);
+
+	let querier: Location =
+		(Parachain(1000), AccountId32 { id: SENDER.into(), network: None }).into();
+	let sent_message = Xcm(vec![QueryResponse {
+		query_id: 0,
+		response: Response::ExecutionResult(None),
+		max_weight: Weight::zero(),
+		querier: Some(querier),
+	}]);
+
+	// The messages were "sent" successfully.
+	assert_eq!(
+		sent_xcm(),
+		vec![
+			(Parent.into(), sent_message.clone()),
+			(Parent.into(), sent_message.clone()),
+			(Parent.into(), sent_message.clone())
+		]
+	);
+}
+
+// Tests the support for `BuyExecution` while the ecosystem transitions to `PayFees`.
+#[test]
+fn buy_execution_works_as_before() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		// We can put everything here, since excess will be returned to holding.
+		// We have to specify `Limited` here to actually work, it's normally
+		// set in the `AllowTopLevelPaidExecutionFrom` barrier.
+		.buy_execution((Here, 100u128), Limited(Weight::from_parts(2, 2)))
+		.deposit_asset(All, RECIPIENT)
+		.build();
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// `BuyExecution` does not interact with the `fees` register.
+	assert_eq!(get_first_fungible(vm.fees()), None);
+
+	// The recipient received all the assets in the holding register, so `100` that
+	// were withdrawn, minus the `4` from paying the execution fees.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 96u128).into()]);
+}
+
+// Tests the interaction between `PayFees` and `RefundSurplus`.
+#[test]
+fn fees_can_be_refunded() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.deposit_asset(All, RECIPIENT)
+		.refund_surplus()
+		.deposit_asset(All, SENDER)
+		.build();
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// Nothing was left in the `fees` register since it was refunded.
+	assert_eq!(get_first_fungible(vm.fees()), None);
+
+	// The recipient received all the assets in the holding register, so `100` that
+	// were withdrawn, minus the `10` that were destinated for fee payment.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]);
+
+	// The sender got back `6` from unused assets.
+	assert_eq!(asset_list(SENDER), [(Here, 6u128).into()]);
+}
+
+// ===== Unhappy path =====
+
+#[test]
+fn putting_all_assets_in_pay_fees() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		.pay_fees((Here, 100u128)) // 100% destined for fees, this is not going to end well...
+		.deposit_asset(All, RECIPIENT)
+		.build();
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// We destined `100` for fee payment, after `4` for execution fees, we are left with `96`.
+	assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 96u128).into());
+
+	// The recipient received no assets since they were all destined for fee payment.
+	assert_eq!(asset_list(RECIPIENT), []);
+}
+
+#[test]
+fn refunding_too_early() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER, (Here, 100u128));
+
+	// Information to send messages.
+	// We don't care about the specifics since we're not actually sending them.
+	let query_response_info =
+		QueryResponseInfo { destination: Parent.into(), query_id: 0, max_weight: Weight::zero() };
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder()
+		.withdraw_asset((Here, 100u128))
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.deposit_asset(All, RECIPIENT)
+		.refund_surplus()
+		.deposit_asset(All, SENDER)
+		// `refund_surplus` cleared the `fees` register.
+		// `holding` is used as a fallback, but we also cleared that.
+		// The instruction will error and the message won't be sent :(.
+		.report_error(query_response_info)
+		.build();
+
+	let (mut vm, _) = instantiate_executor(SENDER, xcm.clone());
+
+	// Program fails to run.
+	assert!(vm.bench_process(xcm).is_err());
+
+	// Nothing is left in the `holding` register.
+	assert_eq!(get_first_fungible(vm.holding()), None);
+	// Nothing was left in the `fees` register since it was refunded.
+	assert_eq!(get_first_fungible(vm.fees()), None);
+
+	// The recipient received all the assets in the holding register, so `100` that
+	// were withdrawn, minus the `10` that were destinated for fee payment.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]);
+
+	// The sender got back `6` from unused assets.
+	assert_eq!(asset_list(SENDER), [(Here, 6u128).into()]);
+
+	// No messages were "sent".
+	assert_eq!(sent_xcm(), Vec::new());
+}
diff --git a/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs b/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs
new file mode 100644
index 00000000000..bc504b8db2a
--- /dev/null
+++ b/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs
@@ -0,0 +1,138 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Unit tests related to the `fees` register and `PayFees` instruction.
+//!
+//! See [Fellowship RFC 105](https://github.com/polkadot-fellows/rfCs/pull/105)
+//! and the [specification](https://github.com/polkadot-fellows/xcm-format) for more information.
+
+use codec::Encode;
+use xcm::prelude::*;
+
+use super::mock::*;
+use crate::XcmExecutor;
+
+#[test]
+fn set_asset_claimer() {
+	let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]);
+	let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]);
+
+	// Make sure the user has enough funds to withdraw.
+	add_asset(sender.clone(), (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		// if withdrawing fails we're not missing any corner case.
+		.withdraw_asset((Here, 100u128))
+		.clear_origin()
+		.set_asset_claimer(bob.clone())
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.build();
+
+	// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we
+	// can inspect its fields.
+	let mut vm =
+		XcmExecutor::<XcmConfig>::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256));
+	vm.message_weight = XcmExecutor::<XcmConfig>::prepare(xcm.clone()).unwrap().weight_of();
+
+	let result = vm.bench_process(xcm);
+	assert!(result.is_ok());
+	assert_eq!(vm.asset_claimer(), Some(bob));
+}
+
+#[test]
+fn do_not_set_asset_claimer_none() {
+	let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]);
+
+	// Make sure the user has enough funds to withdraw.
+	add_asset(sender.clone(), (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		// if withdrawing fails we're not missing any corner case.
+		.withdraw_asset((Here, 100u128))
+		.clear_origin()
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.build();
+
+	// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we
+	// can inspect its fields.
+	let mut vm =
+		XcmExecutor::<XcmConfig>::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256));
+	vm.message_weight = XcmExecutor::<XcmConfig>::prepare(xcm.clone()).unwrap().weight_of();
+
+	let result = vm.bench_process(xcm);
+	assert!(result.is_ok());
+	assert_eq!(vm.asset_claimer(), None);
+}
+
+#[test]
+fn trap_then_set_asset_claimer() {
+	let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]);
+	let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]);
+
+	// Make sure the user has enough funds to withdraw.
+	add_asset(sender.clone(), (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		// if withdrawing fails we're not missing any corner case.
+		.withdraw_asset((Here, 100u128))
+		.clear_origin()
+		.trap(0u64)
+		.set_asset_claimer(bob)
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.build();
+
+	// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we
+	// can inspect its fields.
+	let mut vm =
+		XcmExecutor::<XcmConfig>::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256));
+	vm.message_weight = XcmExecutor::<XcmConfig>::prepare(xcm.clone()).unwrap().weight_of();
+
+	let result = vm.bench_process(xcm);
+	assert!(result.is_err());
+	assert_eq!(vm.asset_claimer(), None);
+}
+
+#[test]
+fn set_asset_claimer_then_trap() {
+	let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]);
+	let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]);
+
+	// Make sure the user has enough funds to withdraw.
+	add_asset(sender.clone(), (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		// if withdrawing fails we're not missing any corner case.
+		.withdraw_asset((Here, 100u128))
+		.clear_origin()
+		.set_asset_claimer(bob.clone())
+		.trap(0u64)
+		.pay_fees((Here, 10u128)) // 10% destined for fees, not more.
+		.build();
+
+	// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we
+	// can inspect its fields.
+	let mut vm =
+		XcmExecutor::<XcmConfig>::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256));
+	vm.message_weight = XcmExecutor::<XcmConfig>::prepare(xcm.clone()).unwrap().weight_of();
+
+	let result = vm.bench_process(xcm);
+	assert!(result.is_err());
+	assert_eq!(vm.asset_claimer(), Some(bob));
+}
diff --git a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs
index b6e303daaad..256f47fec4f 100644
--- a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs
+++ b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs
@@ -39,6 +39,8 @@ pub enum FeeReason {
 	InitiateReserveWithdraw,
 	/// When the `InitiateTeleport` instruction is called.
 	InitiateTeleport,
+	/// When the `InitiateTransfer` instruction is called.
+	InitiateTransfer,
 	/// When the `QueryPallet` instruction is called.
 	QueryPallet,
 	/// When the `ExportMessage` instruction is called (and includes the network ID).
diff --git a/polkadot/xcm/xcm-executor/src/traits/weight.rs b/polkadot/xcm/xcm-executor/src/traits/weight.rs
index 61545c33062..4e41aa5b475 100644
--- a/polkadot/xcm/xcm-executor/src/traits/weight.rs
+++ b/polkadot/xcm/xcm-executor/src/traits/weight.rs
@@ -26,7 +26,7 @@ pub trait WeightBounds<RuntimeCall> {
 
 	/// Return the maximum amount of weight that an attempted execution of this instruction could
 	/// consume.
-	fn instr_weight(instruction: &Instruction<RuntimeCall>) -> Result<Weight, ()>;
+	fn instr_weight(instruction: &mut Instruction<RuntimeCall>) -> Result<Weight, ()>;
 }
 
 /// Charge for weight in order to execute XCM.
diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs
index 4a5de887500..f0a5be908f6 100644
--- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs
+++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs
@@ -144,7 +144,7 @@ parameter_types! {
 	pub const BaseXcmWeight: Weight = Weight::from_parts(100, 10); // Random value.
 	pub const MaxInstructions: u32 = 100;
 	pub const NativeTokenPerSecondPerByte: (AssetId, u128, u128) = (AssetId(HereLocation::get()), 1, 1);
-	pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(2000)].into();
+	pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(2000)].into();
 	pub const HereLocation: Location = Location::here();
 	pub const RelayLocation: Location = Location::parent();
 	pub const MaxAssetsIntoHolding: u32 = 64;
diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs
index 34c1feb6e94..bbac44ed8a1 100644
--- a/polkadot/xcm/xcm-simulator/example/src/tests.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs
@@ -46,7 +46,6 @@ fn dmp() {
 			Parachain(1),
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
-				require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024),
 				call: remark.encode().into(),
 			}]),
 		));
@@ -74,7 +73,6 @@ fn ump() {
 			Parent,
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
-				require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024),
 				call: remark.encode().into(),
 			}]),
 		));
@@ -102,7 +100,6 @@ fn xcmp() {
 			(Parent, Parachain(2)),
 			Xcm(vec![Transact {
 				origin_kind: OriginKind::SovereignAccount,
-				require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024),
 				call: remark.encode().into(),
 			}]),
 		));
@@ -383,7 +380,6 @@ fn reserve_asset_class_create_and_reserve_transfer() {
 
 		let message = Xcm(vec![Transact {
 			origin_kind: OriginKind::Xcm,
-			require_weight_at_most: Weight::from_parts(1_000_000_000, 1024 * 1024),
 			call: parachain::RuntimeCall::from(
 				pallet_uniques::Call::<parachain::Runtime>::create {
 					collection: (Parent, 2u64).into(),
diff --git a/prdoc/pr_4826.prdoc b/prdoc/pr_4826.prdoc
new file mode 100644
index 00000000000..daa4a77e3e8
--- /dev/null
+++ b/prdoc/pr_4826.prdoc
@@ -0,0 +1,69 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: XCMv5
+
+doc:
+  - audience: [Runtime User, Runtime Dev]
+    description: |
+      Added XCMv5.
+
+      This PR brings a new XCM version.
+      It's an amalgamation of multiple individual PRs:
+      - https://github.com/paritytech/polkadot-sdk/pull/6228
+      - https://github.com/paritytech/polkadot-sdk/pull/6148
+      - https://github.com/paritytech/polkadot-sdk/pull/5971
+      - https://github.com/paritytech/polkadot-sdk/pull/5876
+      - https://github.com/paritytech/polkadot-sdk/pull/5420
+      - https://github.com/paritytech/polkadot-sdk/pull/5585
+
+      XCMv5 reduces the potential for bugs by:
+      - Removing the need to specify weight in Transact.
+      - Handling fees in a better way with `PayFees` instead of `BuyExecution`.
+      - Improves asset claiming with `SetAssetClaimer`.
+
+      It also allows some new use-cases like:
+      - Sending both teleported and reserve asset transferred assets in the same cross-chain
+      transfer.
+      - Preserving the origin when doing cross-chain transfers. Allowing the use of Transact
+      in the same message as a cross-chain transfer.
+
+      In version 5, it's expected to change usage of `BuyExecution` to `PayFees`.
+      While `BuyExecution` returns all leftover assets to holding, `PayFees` doesn't.
+      The only way to get funds back from those sent to `PayFees` is by using `RefundSurplus`.
+      Because of this, it's meant to be used alongside the new DryRunApi and XcmPaymentApi.
+      You first dry-run the XCM, get the fees needed, and put them in `PayFees`.
+
+crates:
+  - name: staging-xcm
+    bump: major
+  - name: staging-xcm-builder
+    bump: major
+  - name: staging-xcm-executor
+    bump: major
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: people-westend-runtime
+    bump: minor
+  - name: penpal-runtime
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
+  - name: pallet-xcm-benchmarks
+    bump: minor
+  - name: pallet-multisig
+    bump: minor
diff --git a/prdoc/pr_5390.prdoc b/prdoc/pr_5390.prdoc
new file mode 100644
index 00000000000..cfe6894324a
--- /dev/null
+++ b/prdoc/pr_5390.prdoc
@@ -0,0 +1,55 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Remove NetworkIds for testnets Rococo and Westend
+
+doc:
+  - audience: [Runtime Dev, Runtime User]
+    description: |
+      Implemetation of https://github.com/polkadot-fellows/RFCs/pull/108, in the version 5 of XCM, 
+      Remove `Westend` and `Rococo` from the included `NetworkId`s to improve the stability of the language.
+
+      `NetworkId::Rococo` and `NetworkId::Westend` can just use `NetworkId::ByGenesis` by importing their genesis 
+      block hash
+
+crates:
+  - name: staging-xcm
+    bump: major
+  - name: pallet-xcm-bridge-hub
+    bump: patch
+  - name: snowbridge-pallet-system
+    bump: patch
+  - name: asset-hub-rococo-runtime
+    bump: patch
+  - name: asset-hub-westend-runtime
+    bump: patch
+  - name: bridge-hub-rococo-runtime
+    bump: patch
+  - name: bridge-hub-westend-runtime
+    bump: patch
+  - name: collectives-westend-runtime
+    bump: patch
+  - name: contracts-rococo-runtime
+    bump: patch
+  - name: coretime-rococo-runtime
+    bump: patch
+  - name: coretime-westend-runtime
+    bump: patch
+  - name: glutton-westend-runtime
+    bump: patch
+  - name: people-rococo-runtime
+    bump: patch
+  - name: people-westend-runtime
+    bump: patch
+  - name: penpal-runtime
+    bump: patch
+  - name: rococo-parachain-runtime
+    bump: patch
+  - name: xcm-runtime-apis
+    bump: patch
+  - name: rococo-runtime
+    bump: patch
+  - name: westend-runtime
+    bump: patch
+  - name: assets-common
+    bump: patch
diff --git a/prdoc/pr_5420.prdoc b/prdoc/pr_5420.prdoc
new file mode 100644
index 00000000000..bf8a3456907
--- /dev/null
+++ b/prdoc/pr_5420.prdoc
@@ -0,0 +1,62 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: XCMv5 - Better fee mechanism
+
+doc:
+  - audience:
+    - Runtime User
+    - Runtime Dev
+    description: |
+      In XCMv5, there's a new instruction, `PayFees`, which is meant to be a replacement for `BuyExecution`.
+      This instruction takes only one parameter, the `asset` that you are willing to use for fee payment.
+      There's no parameter for limiting the weight, the amount of the `asset` you put in is the limit of
+      how much you're willing to pay.
+      This instruction works much better with delivery fees.
+      `BuyExecution` will still be around to ensure backwards-compatibility, however, the benefits of the new
+      instruction are a good incentive to switch.
+      The proposed workflow is to estimate fees using the `XcmPaymentApi` and `DryRunApi`, then to put those
+      values in `PayFees` and watch your message go knowing you covered all the necessary fees.
+      You can add a little bit more just in case if you want.
+      `RefundSurplus` now gets back all of the assets that were destined for fee payment so you can deposit
+      them somewhere.
+      BEWARE, make sure you're not sending any other message after you call `RefundSurplus`, if not, it will
+      error.
+
+crates:
+  - name: staging-xcm-executor
+    bump: minor
+  - name: staging-xcm-builder
+    bump: minor
+  - name: staging-xcm
+    bump: major
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
+  - name: xcm-emulator
+    bump: major
+  - name: people-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: emulated-integration-tests-common
+    bump: minor
+  - name: xcm-procedural
+    bump: minor
+  - name: pallet-xcm-benchmarks
+    bump: minor
+  - name: snowbridge-pallet-system
+    bump: patch
diff --git a/prdoc/pr_5585.prdoc b/prdoc/pr_5585.prdoc
new file mode 100644
index 00000000000..d4b115413d4
--- /dev/null
+++ b/prdoc/pr_5585.prdoc
@@ -0,0 +1,47 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Added SetAssetClaimer instruction to XCM v5.
+
+doc:
+  - audience: Runtime Dev 
+    description: |
+      Added SetAssetClaimer implementation to XCM v5. With asset_claimer set users can retrieve their trapped assets
+      at any point in time without the need to go through OpenGov reclaim process.
+
+crates:
+- name: bridge-hub-westend-emulated-chain
+  bump: minor
+- name: asset-hub-westend-integration-tests
+  bump: minor
+- name: asset-hub-rococo-runtime
+  bump: minor
+- name: asset-hub-westend-runtime
+  bump: minor
+- name: bridge-hub-rococo-runtime
+  bump: minor
+- name: bridge-hub-westend-runtime
+  bump: minor
+- name: coretime-rococo-runtime
+  bump: minor
+- name: coretime-westend-runtime
+  bump: minor
+- name: people-rococo-runtime
+  bump: minor
+- name: people-westend-runtime
+  bump: minor
+- name: penpal-runtime
+  bump: minor
+- name: rococo-runtime
+  bump: minor
+- name: westend-runtime
+  bump: minor
+- name: staging-xcm
+  bump: minor
+- name: staging-xcm-executor
+  bump: minor
+- name: pallet-xcm-benchmarks
+  bump: minor
+- name: pallet-multisig
+  bump: minor
+
diff --git a/prdoc/pr_5876.prdoc b/prdoc/pr_5876.prdoc
new file mode 100644
index 00000000000..4e2b8a5c8aa
--- /dev/null
+++ b/prdoc/pr_5876.prdoc
@@ -0,0 +1,99 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: (XCMv5) implement RFC#100, add new InitiateTransfer instruction
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      There's a new XCM instruction in v5: InitiateTransfer.
+      It's meant as a general instruction that will do everything (and more) currently
+      done by InitiateTeleport, InitiateReserveWithdraw and DepositReserveAsset.
+      Its main feature is the ability to do cross-chains transfers mixing teleported and
+      reserve transferred assets.
+      ```rust
+      /// Specify which type of asset transfer is required for a particular `(asset, dest)` combination.
+      pub enum AssetTransferFilter {
+      	/// teleport assets matching `AssetFilter` to `dest`
+      	Teleport(AssetFilter),
+      	/// reserve-transfer assets matching `AssetFilter` to `dest`, using the local chain as reserve
+      	ReserveDeposit(AssetFilter),
+      	/// reserve-transfer assets matching `AssetFilter` to `dest`, using `dest` as reserve
+      	ReserveWithdraw(AssetFilter),
+      }
+      /// Cross-chain transfer matching `assets` in the holding register as follows:
+      ///
+      /// Assets in the holding register are matched using the given list of `AssetTransferFilter`s,
+      /// they are then transferred based on their specified transfer type:
+      ///
+      /// - teleport: burn local assets and append a `ReceiveTeleportedAsset` XCM instruction to
+      ///   the XCM program to be sent onward to the `dest` location,
+      ///
+      /// - reserve deposit: place assets under the ownership of `dest` within this consensus system
+      ///   (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction
+      ///   to the XCM program to be sent onward to the `dest` location,
+      ///
+      /// - reserve withdraw: burn local assets and append a `WithdrawAsset` XCM instruction
+      ///   to the XCM program to be sent onward to the `dest` location,
+      ///
+      /// The onward XCM is then appended a `ClearOrigin` to allow safe execution of any following
+      /// custom XCM instructions provided in `remote_xcm`.
+      ///
+      /// The onward XCM also potentially contains a `BuyExecution` instruction based on the presence
+      /// of the `remote_fees` parameter (see below).
+      ///
+      /// If a transfer requires going through multiple hops, an XCM program can compose this instruction
+      /// to be used at every chain along the path, describing that specific leg of the transfer.
+      ///
+      /// Parameters:
+      /// - `dest`: The location of the transfer next hop.
+      /// - `remote_fees`: If set to `Some(asset_xfer_filter)`, the single asset matching
+      ///   `asset_xfer_filter` in the holding register will be transferred first in the remote XCM
+      ///   program, followed by a `BuyExecution(fee)`, then rest of transfers follow.
+      ///   This guarantees `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom` barrier.
+      /// - `remote_xcm`: Custom instructions that will be executed on the `dest` chain. Note that
+      ///   these instructions will be executed after a `ClearOrigin` so their origin will be `None`.
+      ///
+      /// Safety: No concerns.
+      ///
+      /// Kind: *Command*.
+      ///
+      InitiateTransfer {
+      	destination: Location,
+      	remote_fees: Option<AssetTransferFilter>,
+      	assets: Vec<AssetTransferFilter>,
+      	remote_xcm: Xcm<()>,
+      }
+      ```
+
+crates:
+  - name: emulated-integration-tests-common
+    bump: major
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: people-westend-runtime
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
+  - name: pallet-xcm-benchmarks
+    bump: minor
+  - name: staging-xcm
+    bump: major
+  - name: staging-xcm-executor
+    bump: major
diff --git a/prdoc/pr_5971.prdoc b/prdoc/pr_5971.prdoc
new file mode 100644
index 00000000000..4b1afc4c268
--- /dev/null
+++ b/prdoc/pr_5971.prdoc
@@ -0,0 +1,66 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: XCMv5 InitiateTransfer can preserve original origin across chains.
+
+doc:
+  - audience: Runtime User
+    description: |
+      The new InitiateTransfer instruction can preserve the original origin across chains by
+      setting `preserve_origin: true` in the instruction itself.
+      When it's set to true, it will append after the inner XCM, an `AliasOrigin` instruction
+      instead of the usual `ClearOrigin`.
+      This instruction will try to alias to the original origin, thus preserving it.
+      This only works if the chain receiving the transfer supports the aliasing operation.
+      If not, `preserve_origin: false` works as before and will never fail because of this.
+  - audience: Runtime Dev
+    description: |
+      The new InitiateTransfer instruction can preserve the original origin across chains by
+      setting `preserve_origin: true` in the instruction itself.
+      When it's set to true, it will append after the inner XCM, an `AliasOrigin` instruction
+      instead of the usual `ClearOrigin`.
+      This instruction will try to alias to the original origin, thus preserving it.
+
+      Beware: This only works if the following two rules are followed by the chain receiving such
+      a message.
+      - Alias to interior locations is valid (the exact same behaviour as DescendOrigin)
+      - AssetHub can alias everything (most importantly sibling accounts and ethereum).
+      These can be set with the `Aliasers` configuration item, with the following adapters:
+      - AliasChildLocation
+      - AliasOriginRootUsingFilter with AssetHub and Everything
+      An example of the first one can be seen in `asset-hub-westend` and of the second one in
+      `penpal-runtime`.
+
+crates:
+  - name: staging-xcm
+    bump: minor
+  - name: staging-xcm-builder
+    bump: minor
+  - name: staging-xcm-executor
+    bump: minor
+  - name: pallet-xcm-benchmarks
+    bump: minor
+  - name: snowbridge-router-primitives
+    bump: minor
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: people-westend-runtime
+    bump: minor
+  - name: penpal-runtime
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
diff --git a/prdoc/pr_6228.prdoc b/prdoc/pr_6228.prdoc
new file mode 100644
index 00000000000..4512adf01bb
--- /dev/null
+++ b/prdoc/pr_6228.prdoc
@@ -0,0 +1,50 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Transact without having to specify weight
+
+doc:
+  - audience: [Runtime User, Runtime Dev]
+    description: |
+      In XCMv5, it's no longer required to pass in the expected weight when using
+      `Transact`.
+      This was made to remove a whole class of bugs where the weight specified
+      was not enough.
+
+crates:
+  - name: staging-xcm
+    bump: major
+  - name: staging-xcm-executor
+    bump: major
+  - name: snowbridge-router-primitives
+    bump: minor
+  - name: emulated-integration-tests-common
+    bump: minor
+  - name: cumulus-ping
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: parachains-runtimes-test-utils
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: people-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
+  - name: pallet-xcm-benchmarks
+    bump: minor
+  - name: xcm-simulator-example
+    bump: minor
diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs
index 6a5cf2ac593..a436d6a8ab4 100644
--- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs
+++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs
@@ -33,7 +33,7 @@
 // --pallet
 // pallet_example_mbm
 // --extrinsic
-// 
+//
 // --template
 // substrate/.maintain/frame-weight-template.hbs
 // --output
diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs
index ff682c82ce9..04bedd78cc1 100644
--- a/substrate/frame/system/src/lib.rs
+++ b/substrate/frame/system/src/lib.rs
@@ -130,7 +130,8 @@ use frame_support::traits::BuildGenesisConfig;
 use frame_support::{
 	dispatch::{
 		extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo,
-		DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, PostDispatchInfo,
+		DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, PerDispatchClass,
+		PostDispatchInfo,
 	},
 	ensure, impl_ensure_origin_with_arg_ignoring_arg,
 	migrations::MultiStepMigrator,
@@ -507,6 +508,7 @@ pub mod pallet {
 		type RuntimeCall: Parameter
 			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
 			+ Debug
+			+ GetDispatchInfo
 			+ From<Call<Self>>;
 
 		/// The aggregated `RuntimeTask` type.
-- 
GitLab