From 4875ea11aeef4f3fc7d724940e5ffb703830619b Mon Sep 17 00:00:00 2001
From: Shawn Tabrizi <shawntabrizi@gmail.com>
Date: Mon, 29 Apr 2024 17:22:23 -0400
Subject: [PATCH] Refactor XCM Simulator Example (#4220)

This PR does a "developer experience" refactor of the XCM Simulator
Example.

I was looking for existing code / documentation where developers could
better learn about working with and configuring XCM.

The XCM Simulator was a natural starting point due to the fact that it
can emulate end to end XCM scenarios, without needing to spawn multiple
real chains.

However, the XCM Simulator Example was just 3 giant files with a ton of
configurations, runtime, pallets, and tests mashed together.

This PR breaks down the XCM Simulator Example in a way that I believe is
more approachable by a new developer who is looking to navigate the
various components of the end to end example, and modify it themselves.

The basic structure is:

- xcm simulator example
    - lib (tries to only use the xcm simulator macros)
    - tests
    - relay-chain
        - mod (basic runtime that developers should be familiar with)
        - xcm-config
            - mod (contains the `XcmConfig` type
            - various files for each custom configuration
    - parachain
        - mock_msg_queue (custom pallet for simulator example)
        - mod (basic runtime that developers should be familiar with)
        - xcm-config
            - mod (contains the `XcmConfig` type
            - various files for each custom configuration

I would like to add more documentation to this too, but I think this is
a first step to be accepted which will affect how documentation is added
to the example

---------

Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
---
 polkadot/xcm/xcm-simulator/example/src/lib.rs | 529 +-----------------
 .../xcm-simulator/example/src/parachain.rs    | 470 ----------------
 .../example/src/parachain/mock_msg_queue.rs   | 185 ++++++
 .../example/src/parachain/mod.rs              | 182 ++++++
 .../parachain/xcm_config/asset_transactor.rs  |  39 ++
 .../src/parachain/xcm_config/barrier.rs       |  20 +
 .../src/parachain/xcm_config/constants.rs     |  30 +
 .../xcm_config/location_converter.rs          |  25 +
 .../example/src/parachain/xcm_config/mod.rs   |  63 +++
 .../parachain/xcm_config/origin_converter.rs  |  29 +
 .../src/parachain/xcm_config/reserve.rs       |  21 +
 .../src/parachain/xcm_config/teleporter.rs    |  27 +
 .../src/parachain/xcm_config/weigher.rs       |  27 +
 .../{relay_chain.rs => relay_chain/mod.rs}    | 145 +----
 .../xcm_config/asset_transactor.rs            |  38 ++
 .../src/relay_chain/xcm_config/barrier.rs     |  20 +
 .../src/relay_chain/xcm_config/constants.rs   |  31 +
 .../xcm_config/location_converter.rs          |  25 +
 .../example/src/relay_chain/xcm_config/mod.rs |  62 ++
 .../xcm_config/origin_converter.rs            |  34 ++
 .../src/relay_chain/xcm_config/weigher.rs     |  27 +
 .../xcm/xcm-simulator/example/src/tests.rs    | 513 +++++++++++++++++
 prdoc/pr_4220.prdoc                           |  11 +
 23 files changed, 1435 insertions(+), 1118 deletions(-)
 delete mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs
 rename polkadot/xcm/xcm-simulator/example/src/{relay_chain.rs => relay_chain/mod.rs} (53%)
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs
 create mode 100644 polkadot/xcm/xcm-simulator/example/src/tests.rs
 create mode 100644 prdoc/pr_4220.prdoc

diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs
index 56e204bf571..6fb9a69770e 100644
--- a/polkadot/xcm/xcm-simulator/example/src/lib.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs
@@ -17,13 +17,16 @@
 mod parachain;
 mod relay_chain;
 
+#[cfg(test)]
+mod tests;
+
 use sp_runtime::BuildStorage;
 use sp_tracing;
 use xcm::prelude::*;
 use xcm_executor::traits::ConvertLocation;
 use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt};
 
-pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]);
+pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([1u8; 32]);
 pub const INITIAL_BALANCE: u128 = 1_000_000_000;
 
 decl_test_parachain! {
@@ -68,27 +71,27 @@ decl_test_network! {
 
 pub fn parent_account_id() -> parachain::AccountId {
 	let location = (Parent,);
-	parachain::LocationToAccountId::convert_location(&location.into()).unwrap()
+	parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap()
 }
 
 pub fn child_account_id(para: u32) -> relay_chain::AccountId {
 	let location = (Parachain(para),);
-	relay_chain::LocationToAccountId::convert_location(&location.into()).unwrap()
+	relay_chain::location_converter::LocationConverter::convert_location(&location.into()).unwrap()
 }
 
 pub fn child_account_account_id(para: u32, who: sp_runtime::AccountId32) -> relay_chain::AccountId {
 	let location = (Parachain(para), AccountId32 { network: None, id: who.into() });
-	relay_chain::LocationToAccountId::convert_location(&location.into()).unwrap()
+	relay_chain::location_converter::LocationConverter::convert_location(&location.into()).unwrap()
 }
 
 pub fn sibling_account_account_id(para: u32, who: sp_runtime::AccountId32) -> parachain::AccountId {
 	let location = (Parent, Parachain(para), AccountId32 { network: None, id: who.into() });
-	parachain::LocationToAccountId::convert_location(&location.into()).unwrap()
+	parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap()
 }
 
 pub fn parent_account_account_id(who: sp_runtime::AccountId32) -> parachain::AccountId {
 	let location = (Parent, AccountId32 { network: None, id: who.into() });
-	parachain::LocationToAccountId::convert_location(&location.into()).unwrap()
+	parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap()
 }
 
 pub fn para_ext(para_id: u32) -> sp_io::TestExternalities {
@@ -137,517 +140,3 @@ pub fn relay_ext() -> sp_io::TestExternalities {
 
 pub type RelayChainPalletXcm = pallet_xcm::Pallet<relay_chain::Runtime>;
 pub type ParachainPalletXcm = pallet_xcm::Pallet<parachain::Runtime>;
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	use codec::Encode;
-	use frame_support::{assert_ok, weights::Weight};
-	use xcm::latest::QueryResponseInfo;
-	use xcm_simulator::TestExt;
-
-	// Helper function for forming buy execution message
-	fn buy_execution<C>(fees: impl Into<Asset>) -> Instruction<C> {
-		BuyExecution { fees: fees.into(), weight_limit: Unlimited }
-	}
-
-	#[test]
-	fn remote_account_ids_work() {
-		child_account_account_id(1, ALICE);
-		sibling_account_account_id(1, ALICE);
-		parent_account_account_id(ALICE);
-	}
-
-	#[test]
-	fn dmp() {
-		MockNet::reset();
-
-		let remark = parachain::RuntimeCall::System(
-			frame_system::Call::<parachain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
-		);
-		Relay::execute_with(|| {
-			assert_ok!(RelayChainPalletXcm::send_xcm(
-				Here,
-				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(),
-				}]),
-			));
-		});
-
-		ParaA::execute_with(|| {
-			use parachain::{RuntimeEvent, System};
-			assert!(System::events().iter().any(|r| matches!(
-				r.event,
-				RuntimeEvent::System(frame_system::Event::Remarked { .. })
-			)));
-		});
-	}
-
-	#[test]
-	fn ump() {
-		MockNet::reset();
-
-		let remark = relay_chain::RuntimeCall::System(
-			frame_system::Call::<relay_chain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
-		);
-		ParaA::execute_with(|| {
-			assert_ok!(ParachainPalletXcm::send_xcm(
-				Here,
-				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(),
-				}]),
-			));
-		});
-
-		Relay::execute_with(|| {
-			use relay_chain::{RuntimeEvent, System};
-			assert!(System::events().iter().any(|r| matches!(
-				r.event,
-				RuntimeEvent::System(frame_system::Event::Remarked { .. })
-			)));
-		});
-	}
-
-	#[test]
-	fn xcmp() {
-		MockNet::reset();
-
-		let remark = parachain::RuntimeCall::System(
-			frame_system::Call::<parachain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
-		);
-		ParaA::execute_with(|| {
-			assert_ok!(ParachainPalletXcm::send_xcm(
-				Here,
-				(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(),
-				}]),
-			));
-		});
-
-		ParaB::execute_with(|| {
-			use parachain::{RuntimeEvent, System};
-			assert!(System::events().iter().any(|r| matches!(
-				r.event,
-				RuntimeEvent::System(frame_system::Event::Remarked { .. })
-			)));
-		});
-	}
-
-	#[test]
-	fn reserve_transfer() {
-		MockNet::reset();
-
-		let withdraw_amount = 123;
-
-		Relay::execute_with(|| {
-			assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
-				relay_chain::RuntimeOrigin::signed(ALICE),
-				Box::new(Parachain(1).into()),
-				Box::new(AccountId32 { network: None, id: ALICE.into() }.into()),
-				Box::new((Here, withdraw_amount).into()),
-				0,
-				Unlimited,
-			));
-			assert_eq!(
-				relay_chain::Balances::free_balance(&child_account_id(1)),
-				INITIAL_BALANCE + withdraw_amount
-			);
-		});
-
-		ParaA::execute_with(|| {
-			// free execution, full amount received
-			assert_eq!(
-				pallet_balances::Pallet::<parachain::Runtime>::free_balance(&ALICE),
-				INITIAL_BALANCE + withdraw_amount
-			);
-		});
-	}
-
-	#[test]
-	fn remote_locking_and_unlocking() {
-		MockNet::reset();
-
-		let locked_amount = 100;
-
-		ParaB::execute_with(|| {
-			let message = Xcm(vec![LockAsset {
-				asset: (Here, locked_amount).into(),
-				unlocker: Parachain(1).into(),
-			}]);
-			assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
-		});
-
-		Relay::execute_with(|| {
-			use pallet_balances::{BalanceLock, Reasons};
-			assert_eq!(
-				relay_chain::Balances::locks(&child_account_id(2)),
-				vec![BalanceLock {
-					id: *b"py/xcmlk",
-					amount: locked_amount,
-					reasons: Reasons::All
-				}]
-			);
-		});
-
-		ParaA::execute_with(|| {
-			assert_eq!(
-				parachain::MsgQueue::received_dmp(),
-				vec![Xcm(vec![NoteUnlockable {
-					owner: (Parent, Parachain(2)).into(),
-					asset: (Parent, locked_amount).into()
-				}])]
-			);
-		});
-
-		ParaB::execute_with(|| {
-			// Request unlocking part of the funds on the relay chain
-			let message = Xcm(vec![RequestUnlock {
-				asset: (Parent, locked_amount - 50).into(),
-				locker: Parent.into(),
-			}]);
-			assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message));
-		});
-
-		Relay::execute_with(|| {
-			use pallet_balances::{BalanceLock, Reasons};
-			// Lock is reduced
-			assert_eq!(
-				relay_chain::Balances::locks(&child_account_id(2)),
-				vec![BalanceLock {
-					id: *b"py/xcmlk",
-					amount: locked_amount - 50,
-					reasons: Reasons::All
-				}]
-			);
-		});
-	}
-
-	/// Scenario:
-	/// A parachain transfers an NFT resident on the relay chain to another parachain account.
-	///
-	/// Asserts that the parachain accounts are updated as expected.
-	#[test]
-	fn withdraw_and_deposit_nft() {
-		MockNet::reset();
-
-		Relay::execute_with(|| {
-			assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(1)));
-		});
-
-		ParaA::execute_with(|| {
-			let message = Xcm(vec![TransferAsset {
-				assets: (GeneralIndex(1), 42u32).into(),
-				beneficiary: Parachain(2).into(),
-			}]);
-			// Send withdraw and deposit
-			assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message));
-		});
-
-		Relay::execute_with(|| {
-			assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2)));
-		});
-	}
-
-	/// Scenario:
-	/// The relay-chain teleports an NFT to a parachain.
-	///
-	/// Asserts that the parachain accounts are updated as expected.
-	#[test]
-	fn teleport_nft() {
-		MockNet::reset();
-
-		Relay::execute_with(|| {
-			// Mint the NFT (1, 69) and give it to our "parachain#1 alias".
-			assert_ok!(relay_chain::Uniques::mint(
-				relay_chain::RuntimeOrigin::signed(ALICE),
-				1,
-				69,
-				child_account_account_id(1, ALICE),
-			));
-			// The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be
-			// withdrawable by Alice on the parachain.
-			assert_eq!(
-				relay_chain::Uniques::owner(1, 69),
-				Some(child_account_account_id(1, ALICE))
-			);
-		});
-		ParaA::execute_with(|| {
-			assert_ok!(parachain::ForeignUniques::force_create(
-				parachain::RuntimeOrigin::root(),
-				(Parent, GeneralIndex(1)).into(),
-				ALICE,
-				false,
-			));
-			assert_eq!(
-				parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
-				None,
-			);
-			assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);
-
-			// IRL Alice would probably just execute this locally on the Relay-chain, but we can't
-			// easily do that here since we only send between chains.
-			let message = Xcm(vec![
-				WithdrawAsset((GeneralIndex(1), 69u32).into()),
-				InitiateTeleport {
-					assets: AllCounted(1).into(),
-					dest: Parachain(1).into(),
-					xcm: Xcm(vec![DepositAsset {
-						assets: AllCounted(1).into(),
-						beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
-					}]),
-				},
-			]);
-			// Send teleport
-			let alice = AccountId32 { id: ALICE.into(), network: None };
-			assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
-		});
-		ParaA::execute_with(|| {
-			assert_eq!(
-				parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
-				Some(ALICE),
-			);
-			assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
-		});
-		Relay::execute_with(|| {
-			assert_eq!(relay_chain::Uniques::owner(1, 69), None);
-		});
-	}
-
-	/// Scenario:
-	/// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a
-	/// trustless-backed-derived locally.
-	///
-	/// Asserts that the parachain accounts are updated as expected.
-	#[test]
-	fn reserve_asset_transfer_nft() {
-		sp_tracing::init_for_tests();
-		MockNet::reset();
-
-		Relay::execute_with(|| {
-			assert_ok!(relay_chain::Uniques::force_create(
-				relay_chain::RuntimeOrigin::root(),
-				2,
-				ALICE,
-				false
-			));
-			assert_ok!(relay_chain::Uniques::mint(
-				relay_chain::RuntimeOrigin::signed(ALICE),
-				2,
-				69,
-				child_account_account_id(1, ALICE)
-			));
-			assert_eq!(
-				relay_chain::Uniques::owner(2, 69),
-				Some(child_account_account_id(1, ALICE))
-			);
-		});
-		ParaA::execute_with(|| {
-			assert_ok!(parachain::ForeignUniques::force_create(
-				parachain::RuntimeOrigin::root(),
-				(Parent, GeneralIndex(2)).into(),
-				ALICE,
-				false,
-			));
-			assert_eq!(
-				parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
-				None,
-			);
-			assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);
-
-			let message = Xcm(vec![
-				WithdrawAsset((GeneralIndex(2), 69u32).into()),
-				DepositReserveAsset {
-					assets: AllCounted(1).into(),
-					dest: Parachain(1).into(),
-					xcm: Xcm(vec![DepositAsset {
-						assets: AllCounted(1).into(),
-						beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
-					}]),
-				},
-			]);
-			// Send transfer
-			let alice = AccountId32 { id: ALICE.into(), network: None };
-			assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
-		});
-		ParaA::execute_with(|| {
-			log::debug!(target: "xcm-executor", "Hello");
-			assert_eq!(
-				parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
-				Some(ALICE),
-			);
-			assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
-		});
-
-		Relay::execute_with(|| {
-			assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1)));
-		});
-	}
-
-	/// Scenario:
-	/// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into
-	/// that parachain's sovereign account, who then mints a trustless-backed-derivative locally.
-	///
-	/// Asserts that the parachain accounts are updated as expected.
-	#[test]
-	fn reserve_asset_class_create_and_reserve_transfer() {
-		MockNet::reset();
-
-		Relay::execute_with(|| {
-			assert_ok!(relay_chain::Uniques::force_create(
-				relay_chain::RuntimeOrigin::root(),
-				2,
-				ALICE,
-				false
-			));
-			assert_ok!(relay_chain::Uniques::mint(
-				relay_chain::RuntimeOrigin::signed(ALICE),
-				2,
-				69,
-				child_account_account_id(1, ALICE)
-			));
-			assert_eq!(
-				relay_chain::Uniques::owner(2, 69),
-				Some(child_account_account_id(1, ALICE))
-			);
-
-			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(),
-						admin: parent_account_id(),
-					},
-				)
-				.encode()
-				.into(),
-			}]);
-			// Send creation.
-			assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message));
-		});
-		ParaA::execute_with(|| {
-			// Then transfer
-			let message = Xcm(vec![
-				WithdrawAsset((GeneralIndex(2), 69u32).into()),
-				DepositReserveAsset {
-					assets: AllCounted(1).into(),
-					dest: Parachain(1).into(),
-					xcm: Xcm(vec![DepositAsset {
-						assets: AllCounted(1).into(),
-						beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
-					}]),
-				},
-			]);
-			let alice = AccountId32 { id: ALICE.into(), network: None };
-			assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
-		});
-		ParaA::execute_with(|| {
-			assert_eq!(parachain::Balances::reserved_balance(&parent_account_id()), 1000);
-			assert_eq!(
-				parachain::ForeignUniques::collection_owner((Parent, 2u64).into()),
-				Some(parent_account_id())
-			);
-		});
-	}
-
-	/// Scenario:
-	/// A parachain transfers funds on the relay chain to another parachain account.
-	///
-	/// Asserts that the parachain accounts are updated as expected.
-	#[test]
-	fn withdraw_and_deposit() {
-		MockNet::reset();
-
-		let send_amount = 10;
-
-		ParaA::execute_with(|| {
-			let message = Xcm(vec![
-				WithdrawAsset((Here, send_amount).into()),
-				buy_execution((Here, send_amount)),
-				DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() },
-			]);
-			// Send withdraw and deposit
-			assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
-		});
-
-		Relay::execute_with(|| {
-			assert_eq!(
-				relay_chain::Balances::free_balance(child_account_id(1)),
-				INITIAL_BALANCE - send_amount
-			);
-			assert_eq!(
-				relay_chain::Balances::free_balance(child_account_id(2)),
-				INITIAL_BALANCE + send_amount
-			);
-		});
-	}
-
-	/// Scenario:
-	/// A parachain wants to be notified that a transfer worked correctly.
-	/// It sends a `QueryHolding` after the deposit to get notified on success.
-	///
-	/// Asserts that the balances are updated correctly and the expected XCM is sent.
-	#[test]
-	fn query_holding() {
-		MockNet::reset();
-
-		let send_amount = 10;
-		let query_id_set = 1234;
-
-		// Send a message which fully succeeds on the relay chain
-		ParaA::execute_with(|| {
-			let message = Xcm(vec![
-				WithdrawAsset((Here, send_amount).into()),
-				buy_execution((Here, send_amount)),
-				DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() },
-				ReportHolding {
-					response_info: QueryResponseInfo {
-						destination: Parachain(1).into(),
-						query_id: query_id_set,
-						max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024),
-					},
-					assets: All.into(),
-				},
-			]);
-			// Send withdraw and deposit with query holding
-			assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),));
-		});
-
-		// Check that transfer was executed
-		Relay::execute_with(|| {
-			// Withdraw executed
-			assert_eq!(
-				relay_chain::Balances::free_balance(child_account_id(1)),
-				INITIAL_BALANCE - send_amount
-			);
-			// Deposit executed
-			assert_eq!(
-				relay_chain::Balances::free_balance(child_account_id(2)),
-				INITIAL_BALANCE + send_amount
-			);
-		});
-
-		// Check that QueryResponse message was received
-		ParaA::execute_with(|| {
-			assert_eq!(
-				parachain::MsgQueue::received_dmp(),
-				vec![Xcm(vec![QueryResponse {
-					query_id: query_id_set,
-					response: Response::Assets(Assets::new()),
-					max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024),
-					querier: Some(Here.into()),
-				}])],
-			);
-		});
-	}
-}
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs
deleted file mode 100644
index 41e62596392..00000000000
--- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs
+++ /dev/null
@@ -1,470 +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/>.
-
-//! Parachain runtime mock.
-
-use codec::{Decode, Encode};
-use core::marker::PhantomData;
-use frame_support::{
-	construct_runtime, derive_impl, parameter_types,
-	traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing},
-	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
-};
-
-use frame_system::EnsureRoot;
-use sp_core::{ConstU32, H256};
-use sp_runtime::{
-	traits::{Get, Hash, IdentityLookup},
-	AccountId32,
-};
-use sp_std::prelude::*;
-
-use pallet_xcm::XcmPassthrough;
-use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
-use polkadot_parachain_primitives::primitives::{
-	DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler,
-};
-use xcm::{latest::prelude::*, VersionedXcm};
-use xcm_builder::{
-	Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId,
-	EnsureDecodableXcm, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds,
-	FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, NoChecking,
-	NonFungiblesAdapter, ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative,
-	SignedToAccountId32, SovereignSignedViaLocation,
-};
-use xcm_executor::{
-	traits::{ConvertLocation, JustTry},
-	Config, XcmExecutor,
-};
-
-pub type SovereignAccountOf = (
-	SiblingParachainConvertsVia<Sibling, AccountId>,
-	AccountId32Aliases<RelayNetwork, AccountId>,
-	ParentIsPreset<AccountId>,
-);
-
-pub type AccountId = AccountId32;
-pub type Balance = u128;
-
-parameter_types! {
-	pub const BlockHashCount: u64 = 250;
-}
-
-#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
-impl frame_system::Config for Runtime {
-	type RuntimeOrigin = RuntimeOrigin;
-	type RuntimeCall = RuntimeCall;
-	type Nonce = u64;
-	type Hash = H256;
-	type Hashing = ::sp_runtime::traits::BlakeTwo256;
-	type AccountId = AccountId;
-	type Lookup = IdentityLookup<Self::AccountId>;
-	type Block = Block;
-	type RuntimeEvent = RuntimeEvent;
-	type BlockHashCount = BlockHashCount;
-	type BlockWeights = ();
-	type BlockLength = ();
-	type Version = ();
-	type PalletInfo = PalletInfo;
-	type AccountData = pallet_balances::AccountData<Balance>;
-	type OnNewAccount = ();
-	type OnKilledAccount = ();
-	type DbWeight = ();
-	type BaseCallFilter = Everything;
-	type SystemWeightInfo = ();
-	type SS58Prefix = ();
-	type OnSetCode = ();
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub ExistentialDeposit: Balance = 1;
-	pub const MaxLocks: u32 = 50;
-	pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
-	type MaxLocks = MaxLocks;
-	type Balance = Balance;
-	type RuntimeEvent = RuntimeEvent;
-	type DustRemoval = ();
-	type ExistentialDeposit = ExistentialDeposit;
-	type AccountStore = System;
-	type WeightInfo = ();
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 8];
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type RuntimeFreezeReason = RuntimeFreezeReason;
-	type FreezeIdentifier = ();
-	type MaxFreezes = ConstU32<0>;
-}
-
-#[cfg(feature = "runtime-benchmarks")]
-pub struct UniquesHelper;
-#[cfg(feature = "runtime-benchmarks")]
-impl pallet_uniques::BenchmarkHelper<Location, AssetInstance> for UniquesHelper {
-	fn collection(i: u16) -> Location {
-		GeneralIndex(i as u128).into()
-	}
-	fn item(i: u16) -> AssetInstance {
-		AssetInstance::Index(i as u128)
-	}
-}
-
-impl pallet_uniques::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type CollectionId = Location;
-	type ItemId = AssetInstance;
-	type Currency = Balances;
-	type CreateOrigin = ForeignCreators;
-	type ForceOrigin = frame_system::EnsureRoot<AccountId>;
-	type CollectionDeposit = frame_support::traits::ConstU128<1_000>;
-	type ItemDeposit = frame_support::traits::ConstU128<1_000>;
-	type MetadataDepositBase = frame_support::traits::ConstU128<1_000>;
-	type AttributeDepositBase = frame_support::traits::ConstU128<1_000>;
-	type DepositPerByte = frame_support::traits::ConstU128<1>;
-	type StringLimit = ConstU32<64>;
-	type KeyLimit = ConstU32<64>;
-	type ValueLimit = ConstU32<128>;
-	type Locker = ();
-	type WeightInfo = ();
-	#[cfg(feature = "runtime-benchmarks")]
-	type Helper = UniquesHelper;
-}
-
-// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins
-// which are locations containing the class location.
-pub struct ForeignCreators;
-impl EnsureOriginWithArg<RuntimeOrigin, Location> for ForeignCreators {
-	type Success = AccountId;
-
-	fn try_origin(
-		o: RuntimeOrigin,
-		a: &Location,
-	) -> sp_std::result::Result<Self::Success, RuntimeOrigin> {
-		let origin_location = pallet_xcm::EnsureXcm::<Everything>::try_origin(o.clone())?;
-		if !a.starts_with(&origin_location) {
-			return Err(o)
-		}
-		SovereignAccountOf::convert_location(&origin_location).ok_or(o)
-	}
-
-	#[cfg(feature = "runtime-benchmarks")]
-	fn try_successful_origin(a: &Location) -> Result<RuntimeOrigin, ()> {
-		Ok(pallet_xcm::Origin::Xcm(a.clone()).into())
-	}
-}
-
-parameter_types! {
-	pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
-	pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
-}
-
-parameter_types! {
-	pub const KsmLocation: Location = Location::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Kusama;
-	pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into();
-}
-
-pub type LocationToAccountId = (
-	ParentIsPreset<AccountId>,
-	SiblingParachainConvertsVia<Sibling, AccountId>,
-	AccountId32Aliases<RelayNetwork, AccountId>,
-	Account32Hash<(), AccountId>,
-);
-
-pub type XcmOriginToCallOrigin = (
-	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
-	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
-	XcmPassthrough<RuntimeOrigin>,
-);
-
-parameter_types! {
-	pub const UnitWeightCost: Weight = Weight::from_parts(1, 1);
-	pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1);
-	pub const MaxInstructions: u32 = 100;
-	pub const MaxAssetsIntoHolding: u32 = 64;
-	pub ForeignPrefix: Location = (Parent,).into();
-}
-
-pub type LocalAssetTransactor = (
-	FungibleAdapter<Balances, IsConcrete<KsmLocation>, LocationToAccountId, AccountId, ()>,
-	NonFungiblesAdapter<
-		ForeignUniques,
-		ConvertedConcreteId<Location, AssetInstance, JustTry, JustTry>,
-		SovereignAccountOf,
-		AccountId,
-		NoChecking,
-		(),
-	>,
-);
-
-pub type XcmRouter = EnsureDecodableXcm<super::ParachainXcmRouter<MsgQueue>>;
-pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
-
-parameter_types! {
-	pub NftCollectionOne: AssetFilter
-		= Wild(AllOf { fun: WildNonFungible, id: AssetId((Parent, GeneralIndex(1)).into()) });
-	pub NftCollectionOneForRelay: (AssetFilter, Location)
-		= (NftCollectionOne::get(), (Parent,).into());
-}
-pub type TrustedTeleporters = xcm_builder::Case<NftCollectionOneForRelay>;
-pub type TrustedReserves = EverythingBut<xcm_builder::Case<NftCollectionOneForRelay>>;
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
-	type RuntimeCall = RuntimeCall;
-	type XcmSender = XcmRouter;
-	type AssetTransactor = LocalAssetTransactor;
-	type OriginConverter = XcmOriginToCallOrigin;
-	type IsReserve = (NativeAsset, TrustedReserves);
-	type IsTeleporter = TrustedTeleporters;
-	type UniversalLocation = UniversalLocation;
-	type Barrier = Barrier;
-	type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
-	type Trader = FixedRateOfFungible<KsmPerSecondPerByte, ()>;
-	type ResponseHandler = ();
-	type AssetTrap = ();
-	type AssetLocker = PolkadotXcm;
-	type AssetExchanger = ();
-	type AssetClaims = ();
-	type SubscriptionService = ();
-	type PalletInstancesInfo = ();
-	type FeeManager = ();
-	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
-	type MessageExporter = ();
-	type UniversalAliases = Nothing;
-	type CallDispatcher = RuntimeCall;
-	type SafeCallFilter = Everything;
-	type Aliasers = Nothing;
-	type TransactionalProcessor = FrameTransactionalProcessor;
-	type HrmpNewChannelOpenRequestHandler = ();
-	type HrmpChannelAcceptedHandler = ();
-	type HrmpChannelClosingHandler = ();
-}
-
-#[frame_support::pallet]
-pub mod mock_msg_queue {
-	use super::*;
-	use frame_support::pallet_prelude::*;
-
-	#[pallet::config]
-	pub trait Config: frame_system::Config {
-		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
-		type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
-	}
-
-	#[pallet::call]
-	impl<T: Config> Pallet<T> {}
-
-	#[pallet::pallet]
-	#[pallet::without_storage_info]
-	pub struct Pallet<T>(_);
-
-	#[pallet::storage]
-	#[pallet::getter(fn parachain_id)]
-	pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
-
-	#[pallet::storage]
-	#[pallet::getter(fn received_dmp)]
-	/// A queue of received DMP messages
-	pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
-
-	impl<T: Config> Get<ParaId> for Pallet<T> {
-		fn get() -> ParaId {
-			Self::parachain_id()
-		}
-	}
-
-	pub type MessageId = [u8; 32];
-
-	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
-	pub enum Event<T: Config> {
-		// XCMP
-		/// Some XCM was executed OK.
-		Success(Option<T::Hash>),
-		/// Some XCM failed.
-		Fail(Option<T::Hash>, XcmError),
-		/// Bad XCM version used.
-		BadVersion(Option<T::Hash>),
-		/// Bad XCM format used.
-		BadFormat(Option<T::Hash>),
-
-		// DMP
-		/// Downward message is invalid XCM.
-		InvalidFormat(MessageId),
-		/// Downward message is unsupported version of XCM.
-		UnsupportedVersion(MessageId),
-		/// Downward message executed with the given outcome.
-		ExecutedDownward(MessageId, Outcome),
-	}
-
-	impl<T: Config> Pallet<T> {
-		pub fn set_para_id(para_id: ParaId) {
-			ParachainId::<T>::put(para_id);
-		}
-
-		fn handle_xcmp_message(
-			sender: ParaId,
-			_sent_at: RelayBlockNumber,
-			xcm: VersionedXcm<T::RuntimeCall>,
-			max_weight: Weight,
-		) -> Result<Weight, XcmError> {
-			let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
-			let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
-			let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
-				Ok(xcm) => {
-					let location = (Parent, Parachain(sender.into()));
-					match T::XcmExecutor::prepare_and_execute(
-						location,
-						xcm,
-						&mut message_hash,
-						max_weight,
-						Weight::zero(),
-					) {
-						Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)),
-						Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
-						// As far as the caller is concerned, this was dispatched without error, so
-						// we just report the weight used.
-						Outcome::Incomplete { used, error } =>
-							(Ok(used), Event::Fail(Some(hash), error)),
-					}
-				},
-				Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
-			};
-			Self::deposit_event(event);
-			result
-		}
-	}
-
-	impl<T: Config> XcmpMessageHandler for Pallet<T> {
-		fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
-			iter: I,
-			max_weight: Weight,
-		) -> Weight {
-			for (sender, sent_at, data) in iter {
-				let mut data_ref = data;
-				let _ = XcmpMessageFormat::decode(&mut data_ref)
-					.expect("Simulator encodes with versioned xcm format; qed");
-
-				let mut remaining_fragments = data_ref;
-				while !remaining_fragments.is_empty() {
-					if let Ok(xcm) =
-						VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
-					{
-						let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
-					} else {
-						debug_assert!(false, "Invalid incoming XCMP message data");
-					}
-				}
-			}
-			max_weight
-		}
-	}
-
-	impl<T: Config> DmpMessageHandler for Pallet<T> {
-		fn handle_dmp_messages(
-			iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
-			limit: Weight,
-		) -> Weight {
-			for (_i, (_sent_at, data)) in iter.enumerate() {
-				let mut id = sp_io::hashing::blake2_256(&data[..]);
-				let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
-				match maybe_versioned {
-					Err(_) => {
-						Self::deposit_event(Event::InvalidFormat(id));
-					},
-					Ok(versioned) => match Xcm::try_from(versioned) {
-						Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
-						Ok(x) => {
-							let outcome = T::XcmExecutor::prepare_and_execute(
-								Parent,
-								x.clone(),
-								&mut id,
-								limit,
-								Weight::zero(),
-							);
-							<ReceivedDmp<T>>::append(x);
-							Self::deposit_event(Event::ExecutedDownward(id, outcome));
-						},
-					},
-				}
-			}
-			limit
-		}
-	}
-}
-
-impl mock_msg_queue::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
-
-pub struct TrustedLockerCase<T>(PhantomData<T>);
-impl<T: Get<(Location, AssetFilter)>> ContainsPair<Location, Asset> for TrustedLockerCase<T> {
-	fn contains(origin: &Location, asset: &Asset) -> bool {
-		let (o, a) = T::get();
-		a.matches(asset) && &o == origin
-	}
-}
-
-parameter_types! {
-	pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible }));
-}
-
-pub type TrustedLockers = TrustedLockerCase<RelayTokenForRelay>;
-
-impl pallet_xcm::Config for Runtime {
-	type RuntimeEvent = RuntimeEvent;
-	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
-	type XcmRouter = XcmRouter;
-	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
-	type XcmExecuteFilter = Everything;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type XcmTeleportFilter = Nothing;
-	type XcmReserveTransferFilter = Everything;
-	type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
-	type UniversalLocation = UniversalLocation;
-	type RuntimeOrigin = RuntimeOrigin;
-	type RuntimeCall = RuntimeCall;
-	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
-	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-	type Currency = Balances;
-	type CurrencyMatcher = ();
-	type TrustedLockers = TrustedLockers;
-	type SovereignAccountOf = LocationToAccountId;
-	type MaxLockers = ConstU32<8>;
-	type MaxRemoteLockConsumers = ConstU32<0>;
-	type RemoteLockConsumerIdentifier = ();
-	type WeightInfo = pallet_xcm::TestWeightInfo;
-	type AdminOrigin = EnsureRoot<AccountId>;
-}
-
-type Block = frame_system::mocking::MockBlock<Runtime>;
-
-construct_runtime!(
-	pub enum Runtime
-	{
-		System: frame_system,
-		Balances: pallet_balances,
-		MsgQueue: mock_msg_queue,
-		PolkadotXcm: pallet_xcm,
-		ForeignUniques: pallet_uniques,
-	}
-);
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
new file mode 100644
index 00000000000..17cde921f3e
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
@@ -0,0 +1,185 @@
+// 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/>.
+
+pub use pallet::*;
+use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
+use polkadot_parachain_primitives::primitives::{
+	DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler,
+};
+use sp_runtime::traits::{Get, Hash};
+use xcm::{latest::prelude::*, VersionedXcm};
+
+#[frame_support::pallet]
+pub mod pallet {
+	use super::*;
+	use frame_support::pallet_prelude::*;
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+		type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
+	}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {}
+
+	#[pallet::pallet]
+	#[pallet::without_storage_info]
+	pub struct Pallet<T>(_);
+
+	#[pallet::storage]
+	pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
+
+	#[pallet::storage]
+	/// A queue of received DMP messages
+	pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;
+
+	impl<T: Config> Get<ParaId> for Pallet<T> {
+		fn get() -> ParaId {
+			Self::parachain_id()
+		}
+	}
+
+	pub type MessageId = [u8; 32];
+
+	#[pallet::event]
+	#[pallet::generate_deposit(pub(super) fn deposit_event)]
+	pub enum Event<T: Config> {
+		// XCMP
+		/// Some XCM was executed OK.
+		Success(Option<T::Hash>),
+		/// Some XCM failed.
+		Fail(Option<T::Hash>, XcmError),
+		/// Bad XCM version used.
+		BadVersion(Option<T::Hash>),
+		/// Bad XCM format used.
+		BadFormat(Option<T::Hash>),
+
+		// DMP
+		/// Downward message is invalid XCM.
+		InvalidFormat(MessageId),
+		/// Downward message is unsupported version of XCM.
+		UnsupportedVersion(MessageId),
+		/// Downward message executed with the given outcome.
+		ExecutedDownward(MessageId, Outcome),
+	}
+
+	impl<T: Config> Pallet<T> {
+		/// Get the Parachain Id.
+		pub fn parachain_id() -> ParaId {
+			ParachainId::<T>::get()
+		}
+
+		/// Set the Parachain Id.
+		pub fn set_para_id(para_id: ParaId) {
+			ParachainId::<T>::put(para_id);
+		}
+
+		/// Get the queue of receieved DMP messages.
+		pub fn received_dmp() -> Vec<Xcm<T::RuntimeCall>> {
+			ReceivedDmp::<T>::get()
+		}
+
+		fn handle_xcmp_message(
+			sender: ParaId,
+			_sent_at: RelayBlockNumber,
+			xcm: VersionedXcm<T::RuntimeCall>,
+			max_weight: Weight,
+		) -> Result<Weight, XcmError> {
+			let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
+			let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
+			let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
+				Ok(xcm) => {
+					let location = (Parent, Parachain(sender.into()));
+					match T::XcmExecutor::prepare_and_execute(
+						location,
+						xcm,
+						&mut message_hash,
+						max_weight,
+						Weight::zero(),
+					) {
+						Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)),
+						Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
+						// As far as the caller is concerned, this was dispatched without error, so
+						// we just report the weight used.
+						Outcome::Incomplete { used, error } =>
+							(Ok(used), Event::Fail(Some(hash), error)),
+					}
+				},
+				Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
+			};
+			Self::deposit_event(event);
+			result
+		}
+	}
+
+	impl<T: Config> XcmpMessageHandler for Pallet<T> {
+		fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
+			iter: I,
+			max_weight: Weight,
+		) -> Weight {
+			for (sender, sent_at, data) in iter {
+				let mut data_ref = data;
+				let _ = XcmpMessageFormat::decode(&mut data_ref)
+					.expect("Simulator encodes with versioned xcm format; qed");
+
+				let mut remaining_fragments = data_ref;
+				while !remaining_fragments.is_empty() {
+					if let Ok(xcm) =
+						VersionedXcm::<T::RuntimeCall>::decode(&mut remaining_fragments)
+					{
+						let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
+					} else {
+						debug_assert!(false, "Invalid incoming XCMP message data");
+					}
+				}
+			}
+			max_weight
+		}
+	}
+
+	impl<T: Config> DmpMessageHandler for Pallet<T> {
+		fn handle_dmp_messages(
+			iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
+			limit: Weight,
+		) -> Weight {
+			for (_i, (_sent_at, data)) in iter.enumerate() {
+				let mut id = sp_io::hashing::blake2_256(&data[..]);
+				let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
+				match maybe_versioned {
+					Err(_) => {
+						Self::deposit_event(Event::InvalidFormat(id));
+					},
+					Ok(versioned) => match Xcm::try_from(versioned) {
+						Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
+						Ok(x) => {
+							let outcome = T::XcmExecutor::prepare_and_execute(
+								Parent,
+								x.clone(),
+								&mut id,
+								limit,
+								Weight::zero(),
+							);
+							<ReceivedDmp<T>>::append(x);
+							Self::deposit_event(Event::ExecutedDownward(id, outcome));
+						},
+					},
+				}
+			}
+			limit
+		}
+	}
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
new file mode 100644
index 00000000000..8021f955165
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
@@ -0,0 +1,182 @@
+// 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/>.
+
+//! Parachain runtime mock.
+
+mod mock_msg_queue;
+mod xcm_config;
+pub use xcm_config::*;
+
+use core::marker::PhantomData;
+use frame_support::{
+	construct_runtime, derive_impl, parameter_types,
+	traits::{ConstU128, ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing},
+	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
+};
+use frame_system::EnsureRoot;
+use sp_core::ConstU32;
+use sp_runtime::{
+	traits::{Get, IdentityLookup},
+	AccountId32,
+};
+use sp_std::prelude::*;
+use xcm::latest::prelude::*;
+use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32};
+use xcm_executor::{traits::ConvertLocation, XcmExecutor};
+
+pub type AccountId = AccountId32;
+pub type Balance = u128;
+
+parameter_types! {
+	pub const BlockHashCount: u64 = 250;
+}
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
+impl frame_system::Config for Runtime {
+	type AccountId = AccountId;
+	type Lookup = IdentityLookup<Self::AccountId>;
+	type Block = Block;
+	type AccountData = pallet_balances::AccountData<Balance>;
+}
+
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
+impl pallet_balances::Config for Runtime {
+	type Balance = Balance;
+	type ExistentialDeposit = ConstU128<1>;
+	type AccountStore = System;
+}
+
+#[cfg(feature = "runtime-benchmarks")]
+pub struct UniquesHelper;
+#[cfg(feature = "runtime-benchmarks")]
+impl pallet_uniques::BenchmarkHelper<Location, AssetInstance> for UniquesHelper {
+	fn collection(i: u16) -> Location {
+		GeneralIndex(i as u128).into()
+	}
+	fn item(i: u16) -> AssetInstance {
+		AssetInstance::Index(i as u128)
+	}
+}
+
+impl pallet_uniques::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type CollectionId = Location;
+	type ItemId = AssetInstance;
+	type Currency = Balances;
+	type CreateOrigin = ForeignCreators;
+	type ForceOrigin = frame_system::EnsureRoot<AccountId>;
+	type CollectionDeposit = frame_support::traits::ConstU128<1_000>;
+	type ItemDeposit = frame_support::traits::ConstU128<1_000>;
+	type MetadataDepositBase = frame_support::traits::ConstU128<1_000>;
+	type AttributeDepositBase = frame_support::traits::ConstU128<1_000>;
+	type DepositPerByte = frame_support::traits::ConstU128<1>;
+	type StringLimit = ConstU32<64>;
+	type KeyLimit = ConstU32<64>;
+	type ValueLimit = ConstU32<128>;
+	type Locker = ();
+	type WeightInfo = ();
+	#[cfg(feature = "runtime-benchmarks")]
+	type Helper = UniquesHelper;
+}
+
+// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins
+// which are locations containing the class location.
+pub struct ForeignCreators;
+impl EnsureOriginWithArg<RuntimeOrigin, Location> for ForeignCreators {
+	type Success = AccountId;
+
+	fn try_origin(
+		o: RuntimeOrigin,
+		a: &Location,
+	) -> sp_std::result::Result<Self::Success, RuntimeOrigin> {
+		let origin_location = pallet_xcm::EnsureXcm::<Everything>::try_origin(o.clone())?;
+		if !a.starts_with(&origin_location) {
+			return Err(o);
+		}
+		xcm_config::location_converter::LocationConverter::convert_location(&origin_location)
+			.ok_or(o)
+	}
+
+	#[cfg(feature = "runtime-benchmarks")]
+	fn try_successful_origin(a: &Location) -> Result<RuntimeOrigin, ()> {
+		Ok(pallet_xcm::Origin::Xcm(a.clone()).into())
+	}
+}
+
+parameter_types! {
+	pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
+	pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
+}
+
+impl mock_msg_queue::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+}
+
+pub type LocalOriginToLocation =
+	SignedToAccountId32<RuntimeOrigin, AccountId, constants::RelayNetwork>;
+
+pub struct TrustedLockerCase<T>(PhantomData<T>);
+impl<T: Get<(Location, AssetFilter)>> ContainsPair<Location, Asset> for TrustedLockerCase<T> {
+	fn contains(origin: &Location, asset: &Asset) -> bool {
+		let (o, a) = T::get();
+		a.matches(asset) && &o == origin
+	}
+}
+
+parameter_types! {
+	pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible }));
+}
+
+pub type TrustedLockers = TrustedLockerCase<RelayTokenForRelay>;
+
+impl pallet_xcm::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
+	type XcmRouter = XcmRouter;
+	type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
+	type XcmExecuteFilter = Everything;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+	type XcmTeleportFilter = Nothing;
+	type XcmReserveTransferFilter = Everything;
+	type Weigher = weigher::Weigher;
+	type UniversalLocation = constants::UniversalLocation;
+	type RuntimeOrigin = RuntimeOrigin;
+	type RuntimeCall = RuntimeCall;
+	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
+	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
+	type Currency = Balances;
+	type CurrencyMatcher = ();
+	type TrustedLockers = TrustedLockers;
+	type SovereignAccountOf = location_converter::LocationConverter;
+	type MaxLockers = ConstU32<8>;
+	type MaxRemoteLockConsumers = ConstU32<0>;
+	type RemoteLockConsumerIdentifier = ();
+	type WeightInfo = pallet_xcm::TestWeightInfo;
+	type AdminOrigin = EnsureRoot<AccountId>;
+}
+
+type Block = frame_system::mocking::MockBlock<Runtime>;
+
+construct_runtime!(
+	pub struct Runtime {
+		System: frame_system,
+		Balances: pallet_balances,
+		MsgQueue: mock_msg_queue,
+		PolkadotXcm: pallet_xcm,
+		ForeignUniques: pallet_uniques,
+	}
+);
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs
new file mode 100644
index 00000000000..25cffcf8cef
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs
@@ -0,0 +1,39 @@
+// 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 crate::parachain::{
+	constants::KsmLocation, location_converter::LocationConverter, AccountId, Balances,
+	ForeignUniques,
+};
+use xcm::latest::prelude::*;
+use xcm_builder::{
+	ConvertedConcreteId, FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter,
+};
+use xcm_executor::traits::JustTry;
+
+type LocalAssetTransactor = (
+	FungibleAdapter<Balances, IsConcrete<KsmLocation>, LocationConverter, AccountId, ()>,
+	NonFungiblesAdapter<
+		ForeignUniques,
+		ConvertedConcreteId<Location, AssetInstance, JustTry, JustTry>,
+		LocationConverter,
+		AccountId,
+		NoChecking,
+		(),
+	>,
+);
+
+pub type AssetTransactor = LocalAssetTransactor;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs
new file mode 100644
index 00000000000..1c7aa2c6d32
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs
@@ -0,0 +1,20 @@
+// 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 frame_support::traits::Everything;
+use xcm_builder::AllowUnpaidExecutionFrom;
+
+pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs
new file mode 100644
index 00000000000..f6d0174def8
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs
@@ -0,0 +1,30 @@
+// 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 crate::parachain::MsgQueue;
+use frame_support::parameter_types;
+use xcm::latest::prelude::*;
+
+parameter_types! {
+	pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1);
+	pub const MaxAssetsIntoHolding: u32 = 64;
+}
+
+parameter_types! {
+	pub const KsmLocation: Location = Location::parent();
+	pub const RelayNetwork: NetworkId = NetworkId::Kusama;
+	pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into();
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs
new file mode 100644
index 00000000000..5a54414dd13
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs
@@ -0,0 +1,25 @@
+// 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 crate::parachain::{constants::RelayNetwork, AccountId};
+use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription};
+
+type LocationToAccountId = (
+	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
+	AccountId32Aliases<RelayNetwork, AccountId>,
+);
+
+pub type LocationConverter = LocationToAccountId;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs
new file mode 100644
index 00000000000..0ba02aab9bf
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs
@@ -0,0 +1,63 @@
+// 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/>.
+
+pub mod asset_transactor;
+pub mod barrier;
+pub mod constants;
+pub mod location_converter;
+pub mod origin_converter;
+pub mod reserve;
+pub mod teleporter;
+pub mod weigher;
+
+use crate::parachain::{MsgQueue, PolkadotXcm, RuntimeCall};
+use frame_support::traits::{Everything, Nothing};
+use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor};
+
+// Generated from `decl_test_network!`
+pub type XcmRouter = EnsureDecodableXcm<crate::ParachainXcmRouter<MsgQueue>>;
+
+pub struct XcmConfig;
+impl xcm_executor::Config for XcmConfig {
+	type RuntimeCall = RuntimeCall;
+	type XcmSender = XcmRouter;
+	type AssetTransactor = asset_transactor::AssetTransactor;
+	type OriginConverter = origin_converter::OriginConverter;
+	type IsReserve = reserve::TrustedReserves;
+	type IsTeleporter = teleporter::TrustedTeleporters;
+	type UniversalLocation = constants::UniversalLocation;
+	type Barrier = barrier::Barrier;
+	type Weigher = weigher::Weigher;
+	type Trader = FixedRateOfFungible<constants::KsmPerSecondPerByte, ()>;
+	type ResponseHandler = ();
+	type AssetTrap = ();
+	type AssetLocker = PolkadotXcm;
+	type AssetExchanger = ();
+	type AssetClaims = ();
+	type SubscriptionService = ();
+	type PalletInstancesInfo = ();
+	type FeeManager = ();
+	type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding;
+	type MessageExporter = ();
+	type UniversalAliases = Nothing;
+	type CallDispatcher = RuntimeCall;
+	type SafeCallFilter = Everything;
+	type Aliasers = Nothing;
+	type TransactionalProcessor = FrameTransactionalProcessor;
+	type HrmpNewChannelOpenRequestHandler = ();
+	type HrmpChannelAcceptedHandler = ();
+	type HrmpChannelClosingHandler = ();
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs
new file mode 100644
index 00000000000..5a60f0e6001
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs
@@ -0,0 +1,29 @@
+// 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 crate::parachain::{
+	constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin,
+};
+use pallet_xcm::XcmPassthrough;
+use xcm_builder::{SignedAccountId32AsNative, SovereignSignedViaLocation};
+
+type XcmOriginToCallOrigin = (
+	SovereignSignedViaLocation<LocationConverter, RuntimeOrigin>,
+	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
+	XcmPassthrough<RuntimeOrigin>,
+);
+
+pub type OriginConverter = XcmOriginToCallOrigin;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs
new file mode 100644
index 00000000000..8763a2f37cc
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs
@@ -0,0 +1,21 @@
+// 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 crate::parachain::teleporter::TrustedTeleporters;
+use frame_support::traits::EverythingBut;
+use xcm_builder::NativeAsset;
+
+pub type TrustedReserves = (NativeAsset, EverythingBut<TrustedTeleporters>);
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs
new file mode 100644
index 00000000000..41cb7a5eb2d
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs
@@ -0,0 +1,27 @@
+// 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 frame_support::parameter_types;
+use xcm::latest::prelude::*;
+
+parameter_types! {
+	pub NftCollectionOne: AssetFilter
+		= Wild(AllOf { fun: WildNonFungible, id: AssetId((Parent, GeneralIndex(1)).into()) });
+	pub NftCollectionOneForRelay: (AssetFilter, Location)
+		= (NftCollectionOne::get(), (Parent,).into());
+}
+
+pub type TrustedTeleporters = xcm_builder::Case<NftCollectionOneForRelay>;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs
new file mode 100644
index 00000000000..4bdc98ea3b0
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs
@@ -0,0 +1,27 @@
+// 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 crate::parachain::RuntimeCall;
+use frame_support::parameter_types;
+use xcm::latest::prelude::*;
+use xcm_builder::FixedWeightBounds;
+
+parameter_types! {
+	pub const UnitWeightCost: Weight = Weight::from_parts(1, 1);
+	pub const MaxInstructions: u32 = 100;
+}
+
+pub type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs
similarity index 53%
rename from polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
rename to polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs
index b41df3cfa2b..f698eba41d4 100644
--- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs
@@ -16,31 +16,29 @@
 
 //! Relay chain runtime mock.
 
+mod xcm_config;
+pub use xcm_config::*;
+
 use frame_support::{
 	construct_runtime, derive_impl, parameter_types,
-	traits::{AsEnsureOriginWithArg, Everything, Nothing, ProcessMessage, ProcessMessageError},
+	traits::{
+		AsEnsureOriginWithArg, ConstU128, Everything, Nothing, ProcessMessage, ProcessMessageError,
+	},
 	weights::{Weight, WeightMeter},
 };
 
 use frame_system::EnsureRoot;
-use sp_core::{ConstU32, H256};
+use sp_core::ConstU32;
 use sp_runtime::{traits::IdentityLookup, AccountId32};
 
-use polkadot_parachain_primitives::primitives::Id as ParaId;
 use polkadot_runtime_parachains::{
 	configuration,
 	inclusion::{AggregateMessageOrigin, UmpQueueId},
 	origin, shared,
 };
 use xcm::latest::prelude::*;
-use xcm_builder::{
-	Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex,
-	ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
-	ConvertedConcreteId, EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds,
-	FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter,
-	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
-};
-use xcm_executor::{traits::JustTry, Config, XcmExecutor};
+use xcm_builder::{IsConcrete, SignedToAccountId32};
+use xcm_executor::XcmExecutor;
 
 pub type AccountId = AccountId32;
 pub type Balance = u128;
@@ -51,51 +49,17 @@ parameter_types! {
 
 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
 impl frame_system::Config for Runtime {
-	type RuntimeOrigin = RuntimeOrigin;
-	type RuntimeCall = RuntimeCall;
-	type Nonce = u64;
-	type Hash = H256;
-	type Hashing = ::sp_runtime::traits::BlakeTwo256;
 	type AccountId = AccountId;
 	type Lookup = IdentityLookup<Self::AccountId>;
 	type Block = Block;
-	type RuntimeEvent = RuntimeEvent;
-	type BlockHashCount = BlockHashCount;
-	type BlockWeights = ();
-	type BlockLength = ();
-	type Version = ();
-	type PalletInfo = PalletInfo;
 	type AccountData = pallet_balances::AccountData<Balance>;
-	type OnNewAccount = ();
-	type OnKilledAccount = ();
-	type DbWeight = ();
-	type BaseCallFilter = Everything;
-	type SystemWeightInfo = ();
-	type SS58Prefix = ();
-	type OnSetCode = ();
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub ExistentialDeposit: Balance = 1;
-	pub const MaxLocks: u32 = 50;
-	pub const MaxReserves: u32 = 50;
 }
 
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
 impl pallet_balances::Config for Runtime {
-	type MaxLocks = MaxLocks;
 	type Balance = Balance;
-	type RuntimeEvent = RuntimeEvent;
-	type DustRemoval = ();
-	type ExistentialDeposit = ExistentialDeposit;
+	type ExistentialDeposit = ConstU128<1>;
 	type AccountStore = System;
-	type WeightInfo = ();
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 8];
-	type RuntimeHoldReason = RuntimeHoldReason;
-	type RuntimeFreezeReason = RuntimeFreezeReason;
-	type FreezeIdentifier = ();
-	type MaxFreezes = ConstU32<0>;
 }
 
 impl pallet_uniques::Config for Runtime {
@@ -127,83 +91,8 @@ impl configuration::Config for Runtime {
 	type WeightInfo = configuration::TestWeightInfo;
 }
 
-parameter_types! {
-	pub const TokenLocation: Location = Here.into_location();
-	pub RelayNetwork: NetworkId = ByGenesis([0; 32]);
-	pub const AnyNetwork: Option<NetworkId> = None;
-	pub UniversalLocation: InteriorLocation = RelayNetwork::get().into();
-	pub UnitWeightCost: u64 = 1_000;
-}
-
-pub type LocationToAccountId = (
-	ChildParachainConvertsVia<ParaId, AccountId>,
-	AccountId32Aliases<RelayNetwork, AccountId>,
-	Account32Hash<(), AccountId>,
-);
-
-pub type LocalAssetTransactor = (
-	FungibleAdapter<Balances, IsConcrete<TokenLocation>, LocationToAccountId, AccountId, ()>,
-	NonFungiblesAdapter<
-		Uniques,
-		ConvertedConcreteId<u32, u32, AsPrefixedGeneralIndex<(), u32, JustTry>, JustTry>,
-		LocationToAccountId,
-		AccountId,
-		NoChecking,
-		(),
-	>,
-);
-
-type LocalOriginConverter = (
-	SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
-	ChildParachainAsNative<origin::Origin, RuntimeOrigin>,
-	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
-	ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>,
-);
-
-parameter_types! {
-	pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
-	pub TokensPerSecondPerByte: (AssetId, u128, u128) =
-		(AssetId(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024);
-	pub const MaxInstructions: u32 = 100;
-	pub const MaxAssetsIntoHolding: u32 = 64;
-}
-
-pub type XcmRouter = EnsureDecodableXcm<super::RelayChainXcmRouter>;
-pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
-	type RuntimeCall = RuntimeCall;
-	type XcmSender = XcmRouter;
-	type AssetTransactor = LocalAssetTransactor;
-	type OriginConverter = LocalOriginConverter;
-	type IsReserve = ();
-	type IsTeleporter = ();
-	type UniversalLocation = UniversalLocation;
-	type Barrier = Barrier;
-	type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
-	type Trader = FixedRateOfFungible<TokensPerSecondPerByte, ()>;
-	type ResponseHandler = ();
-	type AssetTrap = ();
-	type AssetLocker = XcmPallet;
-	type AssetExchanger = ();
-	type AssetClaims = ();
-	type SubscriptionService = ();
-	type PalletInstancesInfo = ();
-	type FeeManager = ();
-	type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
-	type MessageExporter = ();
-	type UniversalAliases = Nothing;
-	type CallDispatcher = RuntimeCall;
-	type SafeCallFilter = Everything;
-	type Aliasers = Nothing;
-	type TransactionalProcessor = FrameTransactionalProcessor;
-	type HrmpNewChannelOpenRequestHandler = ();
-	type HrmpChannelAcceptedHandler = ();
-	type HrmpChannelClosingHandler = ();
-}
-
-pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
+pub type LocalOriginToLocation =
+	SignedToAccountId32<RuntimeOrigin, AccountId, constants::RelayNetwork>;
 
 impl pallet_xcm::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
@@ -215,16 +104,16 @@ impl pallet_xcm::Config for Runtime {
 	type XcmExecutor = XcmExecutor<XcmConfig>;
 	type XcmTeleportFilter = Everything;
 	type XcmReserveTransferFilter = Everything;
-	type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
-	type UniversalLocation = UniversalLocation;
+	type Weigher = weigher::Weigher;
+	type UniversalLocation = constants::UniversalLocation;
 	type RuntimeOrigin = RuntimeOrigin;
 	type RuntimeCall = RuntimeCall;
 	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
 	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
 	type Currency = Balances;
-	type CurrencyMatcher = IsConcrete<TokenLocation>;
+	type CurrencyMatcher = IsConcrete<constants::TokenLocation>;
 	type TrustedLockers = ();
-	type SovereignAccountOf = LocationToAccountId;
+	type SovereignAccountOf = location_converter::LocationConverter;
 	type MaxLockers = ConstU32<8>;
 	type MaxRemoteLockConsumers = ConstU32<0>;
 	type RemoteLockConsumerIdentifier = ();
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs
new file mode 100644
index 00000000000..c212569d481
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs
@@ -0,0 +1,38 @@
+// 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 crate::relay_chain::{
+	constants::TokenLocation, location_converter::LocationConverter, AccountId, Balances, Uniques,
+};
+use xcm_builder::{
+	AsPrefixedGeneralIndex, ConvertedConcreteId, FungibleAdapter, IsConcrete, NoChecking,
+	NonFungiblesAdapter,
+};
+use xcm_executor::traits::JustTry;
+
+type LocalAssetTransactor = (
+	FungibleAdapter<Balances, IsConcrete<TokenLocation>, LocationConverter, AccountId, ()>,
+	NonFungiblesAdapter<
+		Uniques,
+		ConvertedConcreteId<u32, u32, AsPrefixedGeneralIndex<(), u32, JustTry>, JustTry>,
+		LocationConverter,
+		AccountId,
+		NoChecking,
+		(),
+	>,
+);
+
+pub type AssetTransactor = LocalAssetTransactor;
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs
new file mode 100644
index 00000000000..1c7aa2c6d32
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs
@@ -0,0 +1,20 @@
+// 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 frame_support::traits::Everything;
+use xcm_builder::AllowUnpaidExecutionFrom;
+
+pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs
new file mode 100644
index 00000000000..f590c42990d
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs
@@ -0,0 +1,31 @@
+// 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 frame_support::parameter_types;
+use xcm::latest::prelude::*;
+
+parameter_types! {
+	pub TokensPerSecondPerByte: (AssetId, u128, u128) =
+		(AssetId(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024);
+	pub const MaxAssetsIntoHolding: u32 = 64;
+}
+
+parameter_types! {
+	pub const TokenLocation: Location = Here.into_location();
+	pub RelayNetwork: NetworkId = ByGenesis([0; 32]);
+	pub UniversalLocation: InteriorLocation = RelayNetwork::get().into();
+	pub UnitWeightCost: u64 = 1_000;
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs
new file mode 100644
index 00000000000..0f5f4e43dc9
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs
@@ -0,0 +1,25 @@
+// 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 crate::relay_chain::{constants::RelayNetwork, AccountId};
+use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription};
+
+type LocationToAccountId = (
+	HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
+	AccountId32Aliases<RelayNetwork, AccountId>,
+);
+
+pub type LocationConverter = LocationToAccountId;
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs
new file mode 100644
index 00000000000..a7a8bae5156
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs
@@ -0,0 +1,62 @@
+// 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/>.
+
+pub mod asset_transactor;
+pub mod barrier;
+pub mod constants;
+pub mod location_converter;
+pub mod origin_converter;
+pub mod weigher;
+
+use crate::relay_chain::{RuntimeCall, XcmPallet};
+use frame_support::traits::{Everything, Nothing};
+use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor};
+use xcm_executor::Config;
+
+// Generated from `decl_test_network!`
+pub type XcmRouter = EnsureDecodableXcm<crate::RelayChainXcmRouter>;
+
+pub struct XcmConfig;
+impl Config for XcmConfig {
+	type RuntimeCall = RuntimeCall;
+	type XcmSender = XcmRouter;
+	type AssetTransactor = asset_transactor::AssetTransactor;
+	type OriginConverter = origin_converter::OriginConverter;
+	type IsReserve = ();
+	type IsTeleporter = ();
+	type UniversalLocation = constants::UniversalLocation;
+	type Barrier = barrier::Barrier;
+	type Weigher = weigher::Weigher;
+	type Trader = FixedRateOfFungible<constants::TokensPerSecondPerByte, ()>;
+	type ResponseHandler = ();
+	type AssetTrap = ();
+	type AssetLocker = XcmPallet;
+	type AssetExchanger = ();
+	type AssetClaims = ();
+	type SubscriptionService = ();
+	type PalletInstancesInfo = ();
+	type FeeManager = ();
+	type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding;
+	type MessageExporter = ();
+	type UniversalAliases = Nothing;
+	type CallDispatcher = RuntimeCall;
+	type SafeCallFilter = Everything;
+	type Aliasers = Nothing;
+	type TransactionalProcessor = FrameTransactionalProcessor;
+	type HrmpNewChannelOpenRequestHandler = ();
+	type HrmpChannelAcceptedHandler = ();
+	type HrmpChannelClosingHandler = ();
+}
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs
new file mode 100644
index 00000000000..3c79912a926
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs
@@ -0,0 +1,34 @@
+// 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 crate::relay_chain::{
+	constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin,
+};
+use polkadot_parachain_primitives::primitives::Id as ParaId;
+use polkadot_runtime_parachains::origin;
+use xcm_builder::{
+	ChildParachainAsNative, ChildSystemParachainAsSuperuser, SignedAccountId32AsNative,
+	SovereignSignedViaLocation,
+};
+
+type LocalOriginConverter = (
+	SovereignSignedViaLocation<LocationConverter, RuntimeOrigin>,
+	ChildParachainAsNative<origin::Origin, RuntimeOrigin>,
+	SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
+	ChildSystemParachainAsSuperuser<ParaId, RuntimeOrigin>,
+);
+
+pub type OriginConverter = LocalOriginConverter;
diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs
new file mode 100644
index 00000000000..5c02565f460
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs
@@ -0,0 +1,27 @@
+// 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 crate::relay_chain::RuntimeCall;
+use frame_support::parameter_types;
+use xcm::latest::prelude::*;
+use xcm_builder::FixedWeightBounds;
+
+parameter_types! {
+	pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
+	pub const MaxInstructions: u32 = 100;
+}
+
+pub type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs
new file mode 100644
index 00000000000..6486a849af3
--- /dev/null
+++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs
@@ -0,0 +1,513 @@
+// 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 crate::*;
+
+use codec::Encode;
+use frame_support::{assert_ok, weights::Weight};
+use xcm::latest::QueryResponseInfo;
+use xcm_simulator::TestExt;
+
+// Helper function for forming buy execution message
+fn buy_execution<C>(fees: impl Into<Asset>) -> Instruction<C> {
+	BuyExecution { fees: fees.into(), weight_limit: Unlimited }
+}
+
+#[test]
+fn remote_account_ids_work() {
+	child_account_account_id(1, ALICE);
+	sibling_account_account_id(1, ALICE);
+	parent_account_account_id(ALICE);
+}
+
+#[test]
+fn dmp() {
+	MockNet::reset();
+
+	let remark = parachain::RuntimeCall::System(
+		frame_system::Call::<parachain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
+	);
+	Relay::execute_with(|| {
+		assert_ok!(RelayChainPalletXcm::send_xcm(
+			Here,
+			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(),
+			}]),
+		));
+	});
+
+	ParaA::execute_with(|| {
+		use parachain::{RuntimeEvent, System};
+		assert!(System::events().iter().any(|r| matches!(
+			r.event,
+			RuntimeEvent::System(frame_system::Event::Remarked { .. })
+		)));
+	});
+}
+
+#[test]
+fn ump() {
+	MockNet::reset();
+
+	let remark = relay_chain::RuntimeCall::System(
+		frame_system::Call::<relay_chain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
+	);
+	ParaA::execute_with(|| {
+		assert_ok!(ParachainPalletXcm::send_xcm(
+			Here,
+			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(),
+			}]),
+		));
+	});
+
+	Relay::execute_with(|| {
+		use relay_chain::{RuntimeEvent, System};
+		assert!(System::events().iter().any(|r| matches!(
+			r.event,
+			RuntimeEvent::System(frame_system::Event::Remarked { .. })
+		)));
+	});
+}
+
+#[test]
+fn xcmp() {
+	MockNet::reset();
+
+	let remark = parachain::RuntimeCall::System(
+		frame_system::Call::<parachain::Runtime>::remark_with_event { remark: vec![1, 2, 3] },
+	);
+	ParaA::execute_with(|| {
+		assert_ok!(ParachainPalletXcm::send_xcm(
+			Here,
+			(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(),
+			}]),
+		));
+	});
+
+	ParaB::execute_with(|| {
+		use parachain::{RuntimeEvent, System};
+		assert!(System::events().iter().any(|r| matches!(
+			r.event,
+			RuntimeEvent::System(frame_system::Event::Remarked { .. })
+		)));
+	});
+}
+
+#[test]
+fn reserve_transfer() {
+	MockNet::reset();
+
+	let withdraw_amount = 123;
+
+	Relay::execute_with(|| {
+		assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets(
+			relay_chain::RuntimeOrigin::signed(ALICE),
+			Box::new(Parachain(1).into()),
+			Box::new(AccountId32 { network: None, id: ALICE.into() }.into()),
+			Box::new((Here, withdraw_amount).into()),
+			0,
+			Unlimited,
+		));
+		assert_eq!(
+			relay_chain::Balances::free_balance(&child_account_id(1)),
+			INITIAL_BALANCE + withdraw_amount
+		);
+	});
+
+	ParaA::execute_with(|| {
+		// free execution, full amount received
+		assert_eq!(
+			pallet_balances::Pallet::<parachain::Runtime>::free_balance(&ALICE),
+			INITIAL_BALANCE + withdraw_amount
+		);
+	});
+}
+
+#[test]
+fn remote_locking_and_unlocking() {
+	MockNet::reset();
+
+	let locked_amount = 100;
+
+	ParaB::execute_with(|| {
+		let message = Xcm(vec![LockAsset {
+			asset: (Here, locked_amount).into(),
+			unlocker: Parachain(1).into(),
+		}]);
+		assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
+	});
+
+	Relay::execute_with(|| {
+		use pallet_balances::{BalanceLock, Reasons};
+		assert_eq!(
+			relay_chain::Balances::locks(&child_account_id(2)),
+			vec![BalanceLock { id: *b"py/xcmlk", amount: locked_amount, reasons: Reasons::All }]
+		);
+	});
+
+	ParaA::execute_with(|| {
+		assert_eq!(
+			parachain::MsgQueue::received_dmp(),
+			vec![Xcm(vec![NoteUnlockable {
+				owner: (Parent, Parachain(2)).into(),
+				asset: (Parent, locked_amount).into()
+			}])]
+		);
+	});
+
+	ParaB::execute_with(|| {
+		// Request unlocking part of the funds on the relay chain
+		let message = Xcm(vec![RequestUnlock {
+			asset: (Parent, locked_amount - 50).into(),
+			locker: Parent.into(),
+		}]);
+		assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message));
+	});
+
+	Relay::execute_with(|| {
+		use pallet_balances::{BalanceLock, Reasons};
+		// Lock is reduced
+		assert_eq!(
+			relay_chain::Balances::locks(&child_account_id(2)),
+			vec![BalanceLock {
+				id: *b"py/xcmlk",
+				amount: locked_amount - 50,
+				reasons: Reasons::All
+			}]
+		);
+	});
+}
+
+/// Scenario:
+/// A parachain transfers an NFT resident on the relay chain to another parachain account.
+///
+/// Asserts that the parachain accounts are updated as expected.
+#[test]
+fn withdraw_and_deposit_nft() {
+	MockNet::reset();
+
+	Relay::execute_with(|| {
+		assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(1)));
+	});
+
+	ParaA::execute_with(|| {
+		let message = Xcm(vec![TransferAsset {
+			assets: (GeneralIndex(1), 42u32).into(),
+			beneficiary: Parachain(2).into(),
+		}]);
+		// Send withdraw and deposit
+		assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message));
+	});
+
+	Relay::execute_with(|| {
+		assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2)));
+	});
+}
+
+/// Scenario:
+/// The relay-chain teleports an NFT to a parachain.
+///
+/// Asserts that the parachain accounts are updated as expected.
+#[test]
+fn teleport_nft() {
+	MockNet::reset();
+
+	Relay::execute_with(|| {
+		// Mint the NFT (1, 69) and give it to our "parachain#1 alias".
+		assert_ok!(relay_chain::Uniques::mint(
+			relay_chain::RuntimeOrigin::signed(ALICE),
+			1,
+			69,
+			child_account_account_id(1, ALICE),
+		));
+		// The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be
+		// withdrawable by Alice on the parachain.
+		assert_eq!(relay_chain::Uniques::owner(1, 69), Some(child_account_account_id(1, ALICE)));
+	});
+	ParaA::execute_with(|| {
+		assert_ok!(parachain::ForeignUniques::force_create(
+			parachain::RuntimeOrigin::root(),
+			(Parent, GeneralIndex(1)).into(),
+			ALICE,
+			false,
+		));
+		assert_eq!(
+			parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
+			None,
+		);
+		assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);
+
+		// IRL Alice would probably just execute this locally on the Relay-chain, but we can't
+		// easily do that here since we only send between chains.
+		let message = Xcm(vec![
+			WithdrawAsset((GeneralIndex(1), 69u32).into()),
+			InitiateTeleport {
+				assets: AllCounted(1).into(),
+				dest: Parachain(1).into(),
+				xcm: Xcm(vec![DepositAsset {
+					assets: AllCounted(1).into(),
+					beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
+				}]),
+			},
+		]);
+		// Send teleport
+		let alice = AccountId32 { id: ALICE.into(), network: None };
+		assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
+	});
+	ParaA::execute_with(|| {
+		assert_eq!(
+			parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
+			Some(ALICE),
+		);
+		assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
+	});
+	Relay::execute_with(|| {
+		assert_eq!(relay_chain::Uniques::owner(1, 69), None);
+	});
+}
+
+/// Scenario:
+/// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a
+/// trustless-backed-derived locally.
+///
+/// Asserts that the parachain accounts are updated as expected.
+#[test]
+fn reserve_asset_transfer_nft() {
+	sp_tracing::init_for_tests();
+	MockNet::reset();
+
+	Relay::execute_with(|| {
+		assert_ok!(relay_chain::Uniques::force_create(
+			relay_chain::RuntimeOrigin::root(),
+			2,
+			ALICE,
+			false
+		));
+		assert_ok!(relay_chain::Uniques::mint(
+			relay_chain::RuntimeOrigin::signed(ALICE),
+			2,
+			69,
+			child_account_account_id(1, ALICE)
+		));
+		assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_account_id(1, ALICE)));
+	});
+	ParaA::execute_with(|| {
+		assert_ok!(parachain::ForeignUniques::force_create(
+			parachain::RuntimeOrigin::root(),
+			(Parent, GeneralIndex(2)).into(),
+			ALICE,
+			false,
+		));
+		assert_eq!(
+			parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
+			None,
+		);
+		assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);
+
+		let message = Xcm(vec![
+			WithdrawAsset((GeneralIndex(2), 69u32).into()),
+			DepositReserveAsset {
+				assets: AllCounted(1).into(),
+				dest: Parachain(1).into(),
+				xcm: Xcm(vec![DepositAsset {
+					assets: AllCounted(1).into(),
+					beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
+				}]),
+			},
+		]);
+		// Send transfer
+		let alice = AccountId32 { id: ALICE.into(), network: None };
+		assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
+	});
+	ParaA::execute_with(|| {
+		log::debug!(target: "xcm-executor", "Hello");
+		assert_eq!(
+			parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
+			Some(ALICE),
+		);
+		assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
+	});
+
+	Relay::execute_with(|| {
+		assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1)));
+	});
+}
+
+/// Scenario:
+/// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into
+/// that parachain's sovereign account, who then mints a trustless-backed-derivative locally.
+///
+/// Asserts that the parachain accounts are updated as expected.
+#[test]
+fn reserve_asset_class_create_and_reserve_transfer() {
+	MockNet::reset();
+
+	Relay::execute_with(|| {
+		assert_ok!(relay_chain::Uniques::force_create(
+			relay_chain::RuntimeOrigin::root(),
+			2,
+			ALICE,
+			false
+		));
+		assert_ok!(relay_chain::Uniques::mint(
+			relay_chain::RuntimeOrigin::signed(ALICE),
+			2,
+			69,
+			child_account_account_id(1, ALICE)
+		));
+		assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_account_id(1, ALICE)));
+
+		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(),
+					admin: parent_account_id(),
+				},
+			)
+			.encode()
+			.into(),
+		}]);
+		// Send creation.
+		assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message));
+	});
+	ParaA::execute_with(|| {
+		// Then transfer
+		let message = Xcm(vec![
+			WithdrawAsset((GeneralIndex(2), 69u32).into()),
+			DepositReserveAsset {
+				assets: AllCounted(1).into(),
+				dest: Parachain(1).into(),
+				xcm: Xcm(vec![DepositAsset {
+					assets: AllCounted(1).into(),
+					beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
+				}]),
+			},
+		]);
+		let alice = AccountId32 { id: ALICE.into(), network: None };
+		assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
+	});
+	ParaA::execute_with(|| {
+		assert_eq!(parachain::Balances::reserved_balance(&parent_account_id()), 1000);
+		assert_eq!(
+			parachain::ForeignUniques::collection_owner((Parent, 2u64).into()),
+			Some(parent_account_id())
+		);
+	});
+}
+
+/// Scenario:
+/// A parachain transfers funds on the relay chain to another parachain account.
+///
+/// Asserts that the parachain accounts are updated as expected.
+#[test]
+fn withdraw_and_deposit() {
+	MockNet::reset();
+
+	let send_amount = 10;
+
+	ParaA::execute_with(|| {
+		let message = Xcm(vec![
+			WithdrawAsset((Here, send_amount).into()),
+			buy_execution((Here, send_amount)),
+			DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() },
+		]);
+		// Send withdraw and deposit
+		assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
+	});
+
+	Relay::execute_with(|| {
+		assert_eq!(
+			relay_chain::Balances::free_balance(child_account_id(1)),
+			INITIAL_BALANCE - send_amount
+		);
+		assert_eq!(
+			relay_chain::Balances::free_balance(child_account_id(2)),
+			INITIAL_BALANCE + send_amount
+		);
+	});
+}
+
+/// Scenario:
+/// A parachain wants to be notified that a transfer worked correctly.
+/// It sends a `QueryHolding` after the deposit to get notified on success.
+///
+/// Asserts that the balances are updated correctly and the expected XCM is sent.
+#[test]
+fn query_holding() {
+	MockNet::reset();
+
+	let send_amount = 10;
+	let query_id_set = 1234;
+
+	// Send a message which fully succeeds on the relay chain
+	ParaA::execute_with(|| {
+		let message = Xcm(vec![
+			WithdrawAsset((Here, send_amount).into()),
+			buy_execution((Here, send_amount)),
+			DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() },
+			ReportHolding {
+				response_info: QueryResponseInfo {
+					destination: Parachain(1).into(),
+					query_id: query_id_set,
+					max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024),
+				},
+				assets: All.into(),
+			},
+		]);
+		// Send withdraw and deposit with query holding
+		assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),));
+	});
+
+	// Check that transfer was executed
+	Relay::execute_with(|| {
+		// Withdraw executed
+		assert_eq!(
+			relay_chain::Balances::free_balance(child_account_id(1)),
+			INITIAL_BALANCE - send_amount
+		);
+		// Deposit executed
+		assert_eq!(
+			relay_chain::Balances::free_balance(child_account_id(2)),
+			INITIAL_BALANCE + send_amount
+		);
+	});
+
+	// Check that QueryResponse message was received
+	ParaA::execute_with(|| {
+		assert_eq!(
+			parachain::MsgQueue::received_dmp(),
+			vec![Xcm(vec![QueryResponse {
+				query_id: query_id_set,
+				response: Response::Assets(Assets::new()),
+				max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024),
+				querier: Some(Here.into()),
+			}])],
+		);
+	});
+}
diff --git a/prdoc/pr_4220.prdoc b/prdoc/pr_4220.prdoc
new file mode 100644
index 00000000000..d5688ab325c
--- /dev/null
+++ b/prdoc/pr_4220.prdoc
@@ -0,0 +1,11 @@
+# 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: Refactor XCM Simulator Example
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      This PR refactors the XCM Simulator Example to improve developer experience when trying to read and understand the example. 3 monolithic files have been broken down into their respective components across various modules. No major logical changes were made.
+
+crates: [ ]
-- 
GitLab