From 4c059c02f45370f284b0e2ba0f0ca8e02400e2d5 Mon Sep 17 00:00:00 2001
From: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Date: Tue, 12 Nov 2024 14:05:52 -0300
Subject: [PATCH] XCMv5: add ExecuteWithOrigin instruction (#6304)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Added `ExecuteWithOrigin` instruction according to the old XCM RFC 38:
https://github.com/polkadot-fellows/xcm-format/pull/38.

This instruction allows you to descend or clear while going back again.

## TODO
- [x] Implementation
- [x] Unit tests
- [x] Integration tests
- [x] Benchmarks
- [x] PRDoc

## Future work

Modify `WithComputedOrigin` barrier to allow, for example, fees to be
paid with a descendant origin using this instruction.

---------

Signed-off-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Andrii <ndk@parity.io>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: Joseph Zhao <65984904+programskillforverification@users.noreply.github.com>
Co-authored-by: Nazar Mokrynskyi <nazar@mokrynskyi.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: command-bot <>
---
 Cargo.lock                                    |  11 +-
 .../tests/assets/asset-hub-westend/Cargo.toml |   1 +
 .../src/tests/claim_assets.rs                 |  82 ++++++++
 .../asset-hub-rococo/src/weights/xcm/mod.rs   |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../asset-hub-westend/src/weights/xcm/mod.rs  |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../bridge-hub-rococo/src/weights/xcm/mod.rs  |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../bridge-hub-westend/src/weights/xcm/mod.rs |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../coretime-rococo/src/weights/xcm/mod.rs    |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../coretime-westend/src/weights/xcm/mod.rs   |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../people-rococo/src/weights/xcm/mod.rs      |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../people-westend/src/weights/xcm/mod.rs     |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      |   7 +
 .../weights/pallet_xcm_benchmarks_generic.rs  |   7 +
 .../runtime/rococo/src/weights/xcm/mod.rs     |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      | 137 +++++++-------
 .../runtime/westend/src/weights/xcm/mod.rs    |   3 +
 .../xcm/pallet_xcm_benchmarks_generic.rs      | 131 +++++++------
 .../src/generic/benchmarking.rs               |  17 ++
 polkadot/xcm/src/v4/mod.rs                    |   7 +-
 polkadot/xcm/src/v5/mod.rs                    |  23 +++
 polkadot/xcm/xcm-builder/src/weight.rs        |   3 +-
 polkadot/xcm/xcm-executor/src/lib.rs          |  51 +++--
 .../src/tests/execute_with_origin.rs          | 177 ++++++++++++++++++
 polkadot/xcm/xcm-executor/src/tests/mod.rs    |   1 +
 prdoc/pr_6304.prdoc                           |  45 +++++
 32 files changed, 630 insertions(+), 149 deletions(-)
 create mode 100644 polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs
 create mode 100644 prdoc/pr_6304.prdoc

diff --git a/Cargo.lock b/Cargo.lock
index eaa0d2667c7..c1eda1b0fb0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -953,6 +953,7 @@ version = "1.0.0"
 dependencies = [
  "assert_matches",
  "asset-test-utils 7.0.0",
+ "assets-common 0.7.0",
  "cumulus-pallet-parachain-system 0.7.0",
  "cumulus-pallet-xcmp-queue 0.7.0",
  "emulated-integration-tests-common",
@@ -20397,7 +20398,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
 dependencies = [
  "bytes",
  "heck 0.5.0",
- "itertools 0.13.0",
+ "itertools 0.12.1",
  "log",
  "multimap",
  "once_cell",
@@ -20443,7 +20444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
 dependencies = [
  "anyhow",
- "itertools 0.13.0",
+ "itertools 0.12.1",
  "proc-macro2 1.0.86",
  "quote 1.0.37",
  "syn 2.0.87",
@@ -20926,7 +20927,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.4.8",
+ "regex-automata 0.4.9",
  "regex-syntax 0.8.5",
 ]
 
@@ -20947,9 +20948,9 @@ checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
 
 [[package]]
 name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
index 71e44e5cee7..7117124b1d1 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml
@@ -37,6 +37,7 @@ pallet-xcm = { workspace = true }
 xcm-runtime-apis = { workspace = true }
 
 # Cumulus
+assets-common = { workspace = true }
 parachains-common = { workspace = true, default-features = true }
 asset-test-utils = { workspace = true, default-features = true }
 cumulus-pallet-xcmp-queue = { workspace = true }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
index 90af907654f..a7f52eb7e09 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs
@@ -17,7 +17,9 @@
 
 use crate::imports::*;
 
+use assets_common::runtime_api::runtime_decl_for_fungibles_api::FungiblesApiV2;
 use emulated_integration_tests_common::test_chain_can_claim_assets;
+use frame_support::traits::fungible::Mutate;
 use xcm_executor::traits::DropAssets;
 
 #[test]
@@ -33,3 +35,83 @@ fn assets_can_be_claimed() {
 		amount
 	);
 }
+
+#[test]
+fn chain_can_claim_assets_for_its_users() {
+	// Many Penpal users have assets trapped in AssetHubWestend.
+	let beneficiaries: Vec<(Location, Assets)> = vec![
+		// Some WND.
+		(
+			Location::new(1, [Parachain(2000), AccountId32 { id: [0u8; 32], network: None }]),
+			(Parent, 10_000_000_000_000u128).into(),
+		),
+		// Some USDT.
+		(
+			Location::new(1, [Parachain(2000), AccountId32 { id: [1u8; 32], network: None }]),
+			([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())], 100_000_000u128)
+				.into(),
+		),
+	];
+
+	// Start with those assets trapped.
+	AssetHubWestend::execute_with(|| {
+		for (location, assets) in &beneficiaries {
+			<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::drop_assets(
+				location,
+				assets.clone().into(),
+				&XcmContext { origin: None, message_id: [0u8; 32], topic: None },
+			);
+		}
+	});
+
+	let penpal_to_asset_hub = PenpalA::sibling_location_of(AssetHubWestend::para_id());
+	let mut builder = Xcm::<()>::builder()
+		.withdraw_asset((Parent, 1_000_000_000_000u128))
+		.pay_fees((Parent, 100_000_000_000u128));
+
+	// Loop through all beneficiaries.
+	for (location, assets) in &beneficiaries {
+		builder = builder.execute_with_origin(
+			// We take only the last part, the `AccountId32` junction.
+			Some((*location.interior().last().unwrap()).into()),
+			Xcm::<()>::builder_unsafe()
+				.claim_asset(assets.clone(), Location::new(0, [GeneralIndex(5)])) // Means lost assets were version 5.
+				.deposit_asset(assets.clone(), location.clone())
+				.build(),
+		)
+	}
+
+	// Finish assembling the message.
+	let message = builder.build();
+
+	// Fund PenpalA's sovereign account on AssetHubWestend so it can pay for fees.
+	AssetHubWestend::execute_with(|| {
+		let penpal_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalA::para_id());
+		let penpal_sov_account_on_asset_hub =
+			AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_asset_hub);
+		type Balances = <AssetHubWestend as AssetHubWestendPallet>::Balances;
+		assert_ok!(<Balances as Mutate<_>>::mint_into(
+			&penpal_sov_account_on_asset_hub,
+			2_000_000_000_000u128,
+		));
+	});
+
+	// We can send a message from Penpal root that claims all those assets for each beneficiary.
+	PenpalA::execute_with(|| {
+		assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
+			<PenpalA as Chain>::RuntimeOrigin::root(),
+			bx!(penpal_to_asset_hub.into()),
+			bx!(VersionedXcm::from(message)),
+		));
+	});
+
+	// We assert beneficiaries have received their funds.
+	AssetHubWestend::execute_with(|| {
+		for (location, expected_assets) in &beneficiaries {
+			let sov_account = AssetHubWestend::sovereign_account_id_of(location.clone());
+			let actual_assets =
+				<AssetHubWestend as Chain>::Runtime::query_account_balances(sov_account).unwrap();
+			assert_eq!(VersionedAssets::from(expected_assets.clone()), actual_assets);
+		}
+	});
+}
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
index bf374fc415c..025c39bcee0 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs
@@ -253,4 +253,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubRococoXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index ef08b432e5c..b69c136b29d 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -373,4 +373,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 668_000 picoseconds.
 		Weight::from_parts(726_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
index 928f1910cbd..35ff2dc367c 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs
@@ -253,4 +253,7 @@ impl<Call> XcmWeightInfo<Call> for AssetHubWestendXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 7098f175d42..52869412311 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -373,4 +373,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 638_000 picoseconds.
 		Weight::from_parts(708_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
index 60a0fc005ca..288aac38563 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs
@@ -256,4 +256,7 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubRococoXcmWeight<Call> {
 	fn set_asset_claimer(_location: &Location) -> Weight {
 		XcmGeneric::<Runtime>::set_asset_claimer()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index b8bd4c4e2d4..bac73e0e056 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -380,4 +380,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
index 473807ea5eb..fa1304d11c6 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs
@@ -257,4 +257,7 @@ impl<Call> XcmWeightInfo<Call> for BridgeHubWestendXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 849456af925..6434f6206fb 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -380,4 +380,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
index 48f1366e2c5..f69736e3145 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs
@@ -254,4 +254,7 @@ impl<Call> XcmWeightInfo<Call> for CoretimeRococoXcmWeight<Call> {
 	fn set_asset_claimer(_location: &Location) -> Weight {
 		XcmGeneric::<Runtime>::set_asset_claimer()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 229dafb7c5e..d207c09ffcd 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -338,4 +338,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
index 1f4b4aa5c5a..1640baa38c9 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs
@@ -254,4 +254,7 @@ impl<Call> XcmWeightInfo<Call> for CoretimeWestendXcmWeight<Call> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index bd70bc4f4bd..fb6e4631736 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -338,4 +338,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
index b82872a1cbf..631cc7b7f0b 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs
@@ -253,4 +253,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleRococoXcmWeight<Call> {
 	fn set_asset_claimer(_location: &Location) -> Weight {
 		XcmGeneric::<Runtime>::set_asset_claimer()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 30e28fac7e5..6aac6119e7e 100644
--- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -338,4 +338,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
index 8ca9771dca4..4b51a3ba411 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs
@@ -253,4 +253,7 @@ impl<Call> XcmWeightInfo<Call> for PeopleWestendXcmWeight<Call> {
 	fn set_asset_claimer(_location: &Location) -> Weight {
 		XcmGeneric::<Runtime>::set_asset_claimer()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<Call>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 3c539902abc..36400f2c1e6 100644
--- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -338,4 +338,11 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 707_000 picoseconds.
 		Weight::from_parts(749_000, 0)
 	}
+	pub fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs
index b62f36172ba..1595a6dfbe4 100644
--- a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs
+++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs
@@ -344,4 +344,11 @@ impl<T: frame_system::Config> pallet_xcm_benchmarks::generic::WeightInfo for Wei
 		Weight::from_parts(1_354_000, 0)
 			.saturating_add(Weight::from_parts(0, 0))
 	}
+	fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(776_000, 0)
+	}
 }
diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
index 007002bf27b..a28b4680087 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs
@@ -289,6 +289,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
 	fn set_asset_claimer(_location: &Location) -> Weight {
 		XcmGeneric::<Runtime>::set_asset_claimer()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<RuntimeCall>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
 
 #[test]
diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 677640b4533..e5915a7986b 100644
--- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-11-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-vcatxqpx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -63,8 +63,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `3746`
-		// Minimum execution time: 64_284_000 picoseconds.
-		Weight::from_parts(65_590_000, 3746)
+		// Minimum execution time: 65_164_000 picoseconds.
+		Weight::from_parts(66_965_000, 3746)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -72,15 +72,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 777_000 picoseconds.
-		Weight::from_parts(825_000, 0)
+		// Minimum execution time: 675_000 picoseconds.
+		Weight::from_parts(745_000, 0)
 	}
 	pub(crate) fn pay_fees() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_543_000 picoseconds.
-		Weight::from_parts(1_627_000, 0)
+		// Minimum execution time: 2_899_000 picoseconds.
+		Weight::from_parts(3_090_000, 0)
+	}
+	pub(crate) fn set_asset_claimer() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 669_000 picoseconds.
+		Weight::from_parts(714_000, 0)
 	}
 	/// Storage: `XcmPallet::Queries` (r:1 w:0)
 	/// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -88,58 +95,65 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3465`
-		// Minimum execution time: 5_995_000 picoseconds.
-		Weight::from_parts(6_151_000, 3465)
+		// Minimum execution time: 6_004_000 picoseconds.
+		Weight::from_parts(6_152_000, 3465)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub(crate) fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_567_000 picoseconds.
-		Weight::from_parts(7_779_000, 0)
+		// Minimum execution time: 7_296_000 picoseconds.
+		Weight::from_parts(7_533_000, 0)
 	}
 	pub(crate) fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_226_000 picoseconds.
-		Weight::from_parts(1_322_000, 0)
+		// Minimum execution time: 1_292_000 picoseconds.
+		Weight::from_parts(1_414_000, 0)
 	}
 	pub(crate) fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 768_000 picoseconds.
-		Weight::from_parts(828_000, 0)
+		// Minimum execution time: 741_000 picoseconds.
+		Weight::from_parts(775_000, 0)
 	}
 	pub(crate) fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 765_000 picoseconds.
-		Weight::from_parts(814_000, 0)
+		// Minimum execution time: 702_000 picoseconds.
+		Weight::from_parts(770_000, 0)
 	}
 	pub(crate) fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 739_000 picoseconds.
-		Weight::from_parts(820_000, 0)
+		// Minimum execution time: 648_000 picoseconds.
+		Weight::from_parts(744_000, 0)
 	}
 	pub(crate) fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 806_000 picoseconds.
-		Weight::from_parts(849_000, 0)
+		// Minimum execution time: 731_000 picoseconds.
+		Weight::from_parts(772_000, 0)
+	}
+	pub(crate) fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 790_000 picoseconds.
+		Weight::from_parts(843_000, 0)
 	}
 	pub(crate) fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 782_000 picoseconds.
-		Weight::from_parts(820_000, 0)
+		// Minimum execution time: 647_000 picoseconds.
+		Weight::from_parts(731_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -155,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `3746`
-		// Minimum execution time: 61_410_000 picoseconds.
-		Weight::from_parts(62_813_000, 3746)
+		// Minimum execution time: 62_808_000 picoseconds.
+		Weight::from_parts(64_413_000, 3746)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -166,8 +180,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `23`
 		//  Estimated: `3488`
-		// Minimum execution time: 9_315_000 picoseconds.
-		Weight::from_parts(9_575_000, 3488)
+		// Minimum execution time: 9_298_000 picoseconds.
+		Weight::from_parts(9_541_000, 3488)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -175,8 +189,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 733_000 picoseconds.
-		Weight::from_parts(813_000, 0)
+		// Minimum execution time: 696_000 picoseconds.
+		Weight::from_parts(732_000, 0)
 	}
 	/// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1)
 	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -192,8 +206,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `180`
 		//  Estimated: `3645`
-		// Minimum execution time: 30_641_000 picoseconds.
-		Weight::from_parts(31_822_000, 3645)
+		// Minimum execution time: 30_585_000 picoseconds.
+		Weight::from_parts(31_622_000, 3645)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -203,44 +217,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_978_000 picoseconds.
-		Weight::from_parts(3_260_000, 0)
+		// Minimum execution time: 3_036_000 picoseconds.
+		Weight::from_parts(3_196_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub(crate) fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_139_000 picoseconds.
-		Weight::from_parts(1_272_000, 0)
+		// Minimum execution time: 1_035_000 picoseconds.
+		Weight::from_parts(1_133_000, 0)
 	}
 	pub(crate) fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 850_000 picoseconds.
-		Weight::from_parts(879_000, 0)
+		// Minimum execution time: 764_000 picoseconds.
+		Weight::from_parts(802_000, 0)
 	}
 	pub(crate) fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 770_000 picoseconds.
-		Weight::from_parts(834_000, 0)
+		// Minimum execution time: 682_000 picoseconds.
+		Weight::from_parts(724_000, 0)
 	}
 	pub(crate) fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 756_000 picoseconds.
-		Weight::from_parts(797_000, 0)
+		// Minimum execution time: 653_000 picoseconds.
+		Weight::from_parts(713_000, 0)
 	}
 	pub(crate) fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 888_000 picoseconds.
-		Weight::from_parts(1_000_000, 0)
+		// Minimum execution time: 857_000 picoseconds.
+		Weight::from_parts(917_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -256,8 +270,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `3746`
-		// Minimum execution time: 72_138_000 picoseconds.
-		Weight::from_parts(73_728_000, 3746)
+		// Minimum execution time: 72_331_000 picoseconds.
+		Weight::from_parts(74_740_000, 3746)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -265,8 +279,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 8_482_000 picoseconds.
-		Weight::from_parts(8_667_000, 0)
+		// Minimum execution time: 8_963_000 picoseconds.
+		Weight::from_parts(9_183_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -282,8 +296,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `281`
 		//  Estimated: `3746`
-		// Minimum execution time: 61_580_000 picoseconds.
-		Weight::from_parts(62_928_000, 3746)
+		// Minimum execution time: 62_555_000 picoseconds.
+		Weight::from_parts(64_824_000, 3746)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -291,29 +305,29 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 807_000 picoseconds.
-		Weight::from_parts(844_000, 0)
+		// Minimum execution time: 740_000 picoseconds.
+		Weight::from_parts(773_000, 0)
 	}
 	pub(crate) fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 757_000 picoseconds.
-		Weight::from_parts(808_000, 0)
+		// Minimum execution time: 678_000 picoseconds.
+		Weight::from_parts(714_000, 0)
 	}
 	pub(crate) fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 740_000 picoseconds.
-		Weight::from_parts(810_000, 0)
+		// Minimum execution time: 656_000 picoseconds.
+		Weight::from_parts(703_000, 0)
 	}
 	pub(crate) fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 752_000 picoseconds.
-		Weight::from_parts(786_000, 0)
+		// Minimum execution time: 672_000 picoseconds.
+		Weight::from_parts(725_000, 0)
 	}
 	pub(crate) fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
@@ -322,11 +336,4 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Minimum execution time: 798_000 picoseconds.
 		Weight::from_parts(845_000, 0)
 	}
-	pub(crate) fn set_asset_claimer() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `0`
-		//  Estimated: `0`
-		// Minimum execution time: 707_000 picoseconds.
-		Weight::from_parts(749_000, 0)
-	}
 }
diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs
index e5f4a0d7ca8..5be9bad824d 100644
--- a/polkadot/runtime/westend/src/weights/xcm/mod.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs
@@ -294,6 +294,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
 	fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
 		XcmGeneric::<Runtime>::unpaid_execution()
 	}
+	fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<RuntimeCall>) -> Weight {
+		XcmGeneric::<Runtime>::execute_with_origin()
+	}
 }
 
 #[test]
diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
index 2ad1cd6359a..076744a5975 100644
--- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
+++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs
@@ -17,9 +17,9 @@
 //! Autogenerated weights for `pallet_xcm_benchmarks::generic`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2024-09-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2024-11-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! HOSTNAME: `runner-vcatxqpx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
 //! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
 
 // Executed Command:
@@ -63,8 +63,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `6196`
-		// Minimum execution time: 67_813_000 picoseconds.
-		Weight::from_parts(69_357_000, 6196)
+		// Minimum execution time: 69_051_000 picoseconds.
+		Weight::from_parts(71_282_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -72,22 +72,22 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 716_000 picoseconds.
-		Weight::from_parts(780_000, 0)
+		// Minimum execution time: 660_000 picoseconds.
+		Weight::from_parts(695_000, 0)
 	}
 	pub(crate) fn pay_fees() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_601_000 picoseconds.
-		Weight::from_parts(1_680_000, 0)
+		// Minimum execution time: 3_096_000 picoseconds.
+		Weight::from_parts(3_313_000, 0)
 	}
 	pub(crate) fn set_asset_claimer() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 707_000 picoseconds.
-		Weight::from_parts(749_000, 0)
+		// Minimum execution time: 661_000 picoseconds.
+		Weight::from_parts(707_000, 0)
 	}
 	/// Storage: `XcmPallet::Queries` (r:1 w:0)
 	/// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -95,58 +95,65 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3465`
-		// Minimum execution time: 6_574_000 picoseconds.
-		Weight::from_parts(6_790_000, 3465)
+		// Minimum execution time: 6_054_000 picoseconds.
+		Weight::from_parts(6_151_000, 3465)
 			.saturating_add(T::DbWeight::get().reads(1))
 	}
 	pub(crate) fn transact() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_232_000 picoseconds.
-		Weight::from_parts(7_422_000, 0)
+		// Minimum execution time: 7_462_000 picoseconds.
+		Weight::from_parts(7_750_000, 0)
 	}
 	pub(crate) fn refund_surplus() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_180_000 picoseconds.
-		Weight::from_parts(1_250_000, 0)
+		// Minimum execution time: 1_378_000 picoseconds.
+		Weight::from_parts(1_454_000, 0)
 	}
 	pub(crate) fn set_error_handler() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 702_000 picoseconds.
-		Weight::from_parts(766_000, 0)
+		// Minimum execution time: 660_000 picoseconds.
+		Weight::from_parts(744_000, 0)
 	}
 	pub(crate) fn set_appendix() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 700_000 picoseconds.
-		Weight::from_parts(757_000, 0)
+		// Minimum execution time: 713_000 picoseconds.
+		Weight::from_parts(755_000, 0)
 	}
 	pub(crate) fn clear_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 686_000 picoseconds.
-		Weight::from_parts(751_000, 0)
+		// Minimum execution time: 632_000 picoseconds.
+		Weight::from_parts(703_000, 0)
 	}
 	pub(crate) fn descend_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 705_000 picoseconds.
-		Weight::from_parts(765_000, 0)
+		// Minimum execution time: 712_000 picoseconds.
+		Weight::from_parts(771_000, 0)
+	}
+	pub(crate) fn execute_with_origin() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `0`
+		//  Estimated: `0`
+		// Minimum execution time: 740_000 picoseconds.
+		Weight::from_parts(826_000, 0)
 	}
 	pub(crate) fn clear_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 687_000 picoseconds.
-		Weight::from_parts(741_000, 0)
+		// Minimum execution time: 653_000 picoseconds.
+		Weight::from_parts(707_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -162,8 +169,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `6196`
-		// Minimum execution time: 65_398_000 picoseconds.
-		Weight::from_parts(67_140_000, 6196)
+		// Minimum execution time: 66_765_000 picoseconds.
+		Weight::from_parts(69_016_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -173,8 +180,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `23`
 		//  Estimated: `3488`
-		// Minimum execution time: 9_653_000 picoseconds.
-		Weight::from_parts(9_944_000, 3488)
+		// Minimum execution time: 9_545_000 picoseconds.
+		Weight::from_parts(9_853_000, 3488)
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
@@ -182,8 +189,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 698_000 picoseconds.
-		Weight::from_parts(759_000, 0)
+		// Minimum execution time: 676_000 picoseconds.
+		Weight::from_parts(723_000, 0)
 	}
 	/// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1)
 	/// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -199,8 +206,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `147`
 		//  Estimated: `3612`
-		// Minimum execution time: 31_300_000 picoseconds.
-		Weight::from_parts(31_989_000, 3612)
+		// Minimum execution time: 31_324_000 picoseconds.
+		Weight::from_parts(32_023_000, 3612)
 			.saturating_add(T::DbWeight::get().reads(5))
 			.saturating_add(T::DbWeight::get().writes(3))
 	}
@@ -210,44 +217,44 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 2_863_000 picoseconds.
-		Weight::from_parts(3_027_000, 0)
+		// Minimum execution time: 3_058_000 picoseconds.
+		Weight::from_parts(3_199_000, 0)
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
 	pub(crate) fn burn_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 1_046_000 picoseconds.
-		Weight::from_parts(1_125_000, 0)
+		// Minimum execution time: 994_000 picoseconds.
+		Weight::from_parts(1_115_000, 0)
 	}
 	pub(crate) fn expect_asset() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 811_000 picoseconds.
-		Weight::from_parts(871_000, 0)
+		// Minimum execution time: 763_000 picoseconds.
+		Weight::from_parts(824_000, 0)
 	}
 	pub(crate) fn expect_origin() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 707_000 picoseconds.
-		Weight::from_parts(741_000, 0)
+		// Minimum execution time: 665_000 picoseconds.
+		Weight::from_parts(712_000, 0)
 	}
 	pub(crate) fn expect_error() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 687_000 picoseconds.
-		Weight::from_parts(741_000, 0)
+		// Minimum execution time: 627_000 picoseconds.
+		Weight::from_parts(695_000, 0)
 	}
 	pub(crate) fn expect_transact_status() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 861_000 picoseconds.
-		Weight::from_parts(931_000, 0)
+		// Minimum execution time: 839_000 picoseconds.
+		Weight::from_parts(889_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -263,8 +270,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `6196`
-		// Minimum execution time: 74_622_000 picoseconds.
-		Weight::from_parts(77_059_000, 6196)
+		// Minimum execution time: 75_853_000 picoseconds.
+		Weight::from_parts(77_515_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -272,8 +279,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 7_603_000 picoseconds.
-		Weight::from_parts(7_871_000, 0)
+		// Minimum execution time: 8_183_000 picoseconds.
+		Weight::from_parts(8_378_000, 0)
 	}
 	/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
 	/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -289,8 +296,8 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `6196`
-		// Minimum execution time: 65_617_000 picoseconds.
-		Weight::from_parts(66_719_000, 6196)
+		// Minimum execution time: 66_576_000 picoseconds.
+		Weight::from_parts(69_465_000, 6196)
 			.saturating_add(T::DbWeight::get().reads(6))
 			.saturating_add(T::DbWeight::get().writes(4))
 	}
@@ -298,35 +305,35 @@ impl<T: frame_system::Config> WeightInfo<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 738_000 picoseconds.
-		Weight::from_parts(779_000, 0)
+		// Minimum execution time: 739_000 picoseconds.
+		Weight::from_parts(773_000, 0)
 	}
 	pub(crate) fn set_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 688_000 picoseconds.
-		Weight::from_parts(755_000, 0)
+		// Minimum execution time: 648_000 picoseconds.
+		Weight::from_parts(693_000, 0)
 	}
 	pub(crate) fn clear_topic() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 684_000 picoseconds.
-		Weight::from_parts(722_000, 0)
+		// Minimum execution time: 654_000 picoseconds.
+		Weight::from_parts(700_000, 0)
 	}
 	pub(crate) fn set_fees_mode() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 694_000 picoseconds.
-		Weight::from_parts(738_000, 0)
+		// Minimum execution time: 646_000 picoseconds.
+		Weight::from_parts(702_000, 0)
 	}
 	pub(crate) fn unpaid_execution() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `0`
-		// Minimum execution time: 713_000 picoseconds.
-		Weight::from_parts(776_000, 0)
+		// Minimum execution time: 665_000 picoseconds.
+		Weight::from_parts(714_000, 0)
 	}
 }
diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
index 0d80ef89a1c..87bf27e4ff1 100644
--- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
+++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
@@ -229,6 +229,23 @@ benchmarks! {
 		);
 	}
 
+	execute_with_origin {
+		let mut executor = new_executor::<T>(Default::default());
+		let who: Junctions = Junctions::from([AccountId32 { id: [0u8; 32], network: None }]);
+		let instruction = Instruction::ExecuteWithOrigin { descendant_origin: Some(who.clone()), xcm: Xcm(vec![]) };
+		let xcm = Xcm(vec![instruction]);
+	}: {
+		executor.bench_process(xcm)?;
+	} verify {
+		assert_eq!(
+			executor.origin(),
+			&Some(Location {
+				parents: 0,
+				interior: Here,
+			}),
+		);
+	}
+
 	clear_origin {
 		let mut executor = new_executor::<T>(Default::default());
 		let instruction = Instruction::ClearOrigin;
diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs
index 545b75a99ff..9baf58eacfb 100644
--- a/polkadot/xcm/src/v4/mod.rs
+++ b/polkadot/xcm/src/v4/mod.rs
@@ -1421,8 +1421,11 @@ impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instructi
 				weight_limit,
 				check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
 			},
-			InitiateTransfer { .. } | PayFees { .. } | SetAssetClaimer { .. } => {
-				log::debug!(target: "xcm::v5tov4", "`{new_instruction:?}` not supported by v4");
+			InitiateTransfer { .. } |
+			PayFees { .. } |
+			SetAssetClaimer { .. } |
+			ExecuteWithOrigin { .. } => {
+				log::debug!(target: "xcm::versions::v5tov4", "`{new_instruction:?}` not supported by v4");
 				return Err(());
 			},
 		})
diff --git a/polkadot/xcm/src/v5/mod.rs b/polkadot/xcm/src/v5/mod.rs
index d455fa48ada..830b23cc44b 100644
--- a/polkadot/xcm/src/v5/mod.rs
+++ b/polkadot/xcm/src/v5/mod.rs
@@ -1109,6 +1109,25 @@ pub enum Instruction<Call> {
 		assets: Vec<AssetTransferFilter>,
 		remote_xcm: Xcm<()>,
 	},
+
+	/// Executes inner `xcm` with origin set to the provided `descendant_origin`. Once the inner
+	/// `xcm` is executed, the original origin (the one active for this instruction) is restored.
+	///
+	/// Parameters:
+	/// - `descendant_origin`: The origin that will be used during the execution of the inner
+	///   `xcm`. If set to `None`, the inner `xcm` is executed with no origin. If set to `Some(o)`,
+	///   the inner `xcm` is executed as if there was a `DescendOrigin(o)` executed before it, and
+	///   runs the inner xcm with origin: `original_origin.append_with(o)`.
+	/// - `xcm`: Inner instructions that will be executed with the origin modified according to
+	///   `descendant_origin`.
+	///
+	/// Safety: No concerns.
+	///
+	/// Kind: *Command*
+	///
+	/// Errors:
+	/// - `BadOrigin`
+	ExecuteWithOrigin { descendant_origin: Option<InteriorLocation>, xcm: Xcm<Call> },
 }
 
 impl<Call> Xcm<Call> {
@@ -1189,6 +1208,8 @@ impl<Call> Instruction<Call> {
 			PayFees { asset } => PayFees { asset },
 			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
 				InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm },
+			ExecuteWithOrigin { descendant_origin, xcm } =>
+				ExecuteWithOrigin { descendant_origin, xcm: xcm.into() },
 		}
 	}
 }
@@ -1261,6 +1282,8 @@ impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
 			PayFees { asset } => W::pay_fees(asset),
 			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
 				W::initiate_transfer(destination, remote_fees, preserve_origin, assets, remote_xcm),
+			ExecuteWithOrigin { descendant_origin, xcm } =>
+				W::execute_with_origin(descendant_origin, xcm),
 		}
 	}
 }
diff --git a/polkadot/xcm/xcm-builder/src/weight.rs b/polkadot/xcm/xcm-builder/src/weight.rs
index f8c0275d0f5..6521121f2c9 100644
--- a/polkadot/xcm/xcm-builder/src/weight.rs
+++ b/polkadot/xcm/xcm-builder/src/weight.rs
@@ -65,7 +65,8 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo, M> FixedWeightBounds<T, C, M>
 	) -> Result<Weight, ()> {
 		let instr_weight = match instruction {
 			Transact { ref mut call, .. } => call.ensure_decoded()?.get_dispatch_info().call_weight,
-			SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?,
+			SetErrorHandler(xcm) | SetAppendix(xcm) | ExecuteWithOrigin { xcm, .. } =>
+				Self::weight_with_limit(xcm, instrs_limit)?,
 			_ => Weight::zero(),
 		};
 		T::get().checked_add(&instr_weight).ok_or(())
diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs
index e33f94389b2..4e051f24050 100644
--- a/polkadot/xcm/xcm-executor/src/lib.rs
+++ b/polkadot/xcm/xcm-executor/src/lib.rs
@@ -314,7 +314,7 @@ impl<Config: config::Config> FeeManager for XcmExecutor<Config> {
 	}
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 pub struct ExecutorError {
 	pub index: u32,
 	pub xcm_error: XcmError,
@@ -1041,19 +1041,25 @@ impl<Config: config::Config> XcmExecutor<Config> {
 				);
 				Ok(())
 			},
-			DescendOrigin(who) => self
-				.context
-				.origin
-				.as_mut()
-				.ok_or(XcmError::BadOrigin)?
-				.append_with(who)
-				.map_err(|e| {
-					tracing::error!(target: "xcm::process_instruction::descend_origin", ?e, "Failed to append junctions");
-					XcmError::LocationFull
-				}),
-			ClearOrigin => {
-				self.context.origin = None;
-				Ok(())
+			DescendOrigin(who) => self.do_descend_origin(who),
+			ClearOrigin => self.do_clear_origin(),
+			ExecuteWithOrigin { descendant_origin, xcm } => {
+				let previous_origin = self.context.origin.clone();
+
+				// Set new temporary origin.
+				if let Some(who) = descendant_origin {
+					self.do_descend_origin(who)?;
+				} else {
+					self.do_clear_origin()?;
+				}
+				// Process instructions.
+				let result = self.process(xcm).map_err(|error| {
+					tracing::error!(target: "xcm::execute", ?error, actual_origin = ?self.context.origin, original_origin = ?previous_origin, "ExecuteWithOrigin inner xcm failure");
+					error.xcm_error
+				});
+				// Reset origin to previous one.
+				self.context.origin = previous_origin;
+				result
 			},
 			ReportError(response_info) => {
 				// Report the given result by sending a QueryResponse XCM to a previously given
@@ -1643,6 +1649,23 @@ impl<Config: config::Config> XcmExecutor<Config> {
 		}
 	}
 
+	fn do_descend_origin(&mut self, who: InteriorLocation) -> XcmResult {
+		self.context
+			.origin
+			.as_mut()
+			.ok_or(XcmError::BadOrigin)?
+			.append_with(who)
+			.map_err(|e| {
+				tracing::error!(target: "xcm::do_descend_origin", ?e, "Failed to append junctions");
+				XcmError::LocationFull
+			})
+	}
+
+	fn do_clear_origin(&mut self) -> XcmResult {
+		self.context.origin = None;
+		Ok(())
+	}
+
 	/// Deposit `to_deposit` assets to `beneficiary`, without giving up on the first (transient)
 	/// error, and retrying once just in case one of the subsequently deposited assets satisfy some
 	/// requirement.
diff --git a/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs b/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs
new file mode 100644
index 00000000000..daba8ae1c03
--- /dev/null
+++ b/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs
@@ -0,0 +1,177 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Unit tests for the `ExecuteWithOrigin` instruction.
+//!
+//! See the [XCM RFC](https://github.com/polkadot-fellows/xcm-format/pull/38)
+//! and the [specification](https://github.com/polkadot-fellows/xcm-format/tree/8cef08e375c6f6d3966909ccf773ed46ac703917) for more information.
+//!
+//! The XCM RFCs were moved to the fellowship RFCs but this one was approved and merged before that.
+
+use xcm::prelude::*;
+
+use super::mock::*;
+use crate::ExecutorError;
+
+// The sender and recipient we use across these tests.
+const SENDER_1: [u8; 32] = [0; 32];
+const SENDER_2: [u8; 32] = [1; 32];
+const RECIPIENT: [u8; 32] = [2; 32];
+
+// ===== Happy path =====
+
+// In this test, root descends into one account to pay fees, pops that origin
+// and descends into a second account to withdraw funds.
+// These assets can now be used to perform actions as root.
+#[test]
+fn root_can_descend_into_more_than_one_account() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER_1, (Here, 10u128));
+	add_asset(SENDER_2, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		.execute_with_origin(
+			Some(SENDER_1.into()),
+			Xcm::<TestCall>::builder_unsafe()
+				.withdraw_asset((Here, 10u128))
+				.pay_fees((Here, 10u128))
+				.build(),
+		)
+		.execute_with_origin(
+			Some(SENDER_2.into()),
+			Xcm::<TestCall>::builder_unsafe().withdraw_asset((Here, 100u128)).build(),
+		)
+		.expect_origin(Some(Here.into()))
+		.deposit_asset(All, RECIPIENT)
+		.build();
+
+	let (mut vm, weight) = instantiate_executor(Here, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+	assert!(vm.bench_post_process(weight).ensure_complete().is_ok());
+
+	// RECIPIENT gets the funds.
+	assert_eq!(asset_list(RECIPIENT), [(Here, 100u128).into()]);
+}
+
+// ExecuteWithOrigin works for clearing the origin as well.
+#[test]
+fn works_for_clearing_origin() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER_1, (Here, 100u128));
+
+	// Build xcm.
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		// Root code.
+		.expect_origin(Some(Here.into()))
+		.execute_with_origin(
+			None,
+			// User code, we run it with no origin.
+			Xcm::<TestCall>::builder_unsafe().expect_origin(None).build(),
+		)
+		// We go back to root code.
+		.build();
+
+	let (mut vm, weight) = instantiate_executor(Here, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+	assert!(vm.bench_post_process(weight).ensure_complete().is_ok());
+}
+
+// Setting the error handler or appendix inside of `ExecuteWithOrigin`
+// will work as expected.
+#[test]
+fn set_error_handler_and_appendix_work() {
+	add_asset(SENDER_1, (Here, 110u128));
+
+	let xcm = Xcm::<TestCall>::builder_unsafe()
+		.execute_with_origin(
+			Some(SENDER_1.into()),
+			Xcm::<TestCall>::builder_unsafe()
+				.withdraw_asset((Here, 110u128))
+				.pay_fees((Here, 10u128))
+				.set_error_handler(
+					Xcm::<TestCall>::builder_unsafe()
+						.deposit_asset(vec![(Here, 10u128).into()], SENDER_2)
+						.build(),
+				)
+				.set_appendix(
+					Xcm::<TestCall>::builder_unsafe().deposit_asset(All, RECIPIENT).build(),
+				)
+				.build(),
+		)
+		.build();
+
+	let (mut vm, weight) = instantiate_executor(Here, xcm.clone());
+
+	// Program runs successfully.
+	assert!(vm.bench_process(xcm).is_ok());
+
+	assert_eq!(
+		vm.error_handler(),
+		&Xcm::<TestCall>(vec![DepositAsset {
+			assets: vec![Asset { id: AssetId(Location::new(0, [])), fun: Fungible(10) }].into(),
+			beneficiary: Location::new(0, [AccountId32 { id: SENDER_2, network: None }]),
+		},])
+	);
+	assert_eq!(
+		vm.appendix(),
+		&Xcm::<TestCall>(vec![DepositAsset {
+			assets: All.into(),
+			beneficiary: Location::new(0, [AccountId32 { id: RECIPIENT, network: None }]),
+		},])
+	);
+
+	assert!(vm.bench_post_process(weight).ensure_complete().is_ok());
+}
+
+// ===== Unhappy path =====
+
+// Processing still can't be called recursively more than the limit.
+#[test]
+fn recursion_exceeds_limit() {
+	// Make sure the sender has enough funds to withdraw.
+	add_asset(SENDER_1, (Here, 10u128));
+	add_asset(SENDER_2, (Here, 100u128));
+
+	let mut xcm = Xcm::<TestCall>::builder_unsafe()
+		.execute_with_origin(None, Xcm::<TestCall>::builder_unsafe().clear_origin().build())
+		.build();
+
+	// 10 is the RECURSION_LIMIT.
+	for _ in 0..10 {
+		let clone_of_xcm = xcm.clone();
+		if let ExecuteWithOrigin { xcm: ref mut inner, .. } = xcm.inner_mut()[0] {
+			*inner = clone_of_xcm;
+		}
+	}
+
+	let (mut vm, weight) = instantiate_executor(Here, xcm.clone());
+
+	// Program errors with `ExceedsStackLimit`.
+	assert_eq!(
+		vm.bench_process(xcm),
+		Err(ExecutorError {
+			index: 0,
+			xcm_error: XcmError::ExceedsStackLimit,
+			weight: Weight::zero(),
+		})
+	);
+	assert!(vm.bench_post_process(weight).ensure_complete().is_ok());
+}
diff --git a/polkadot/xcm/xcm-executor/src/tests/mod.rs b/polkadot/xcm/xcm-executor/src/tests/mod.rs
index 5c133871f0b..15a0565e357 100644
--- a/polkadot/xcm/xcm-executor/src/tests/mod.rs
+++ b/polkadot/xcm/xcm-executor/src/tests/mod.rs
@@ -20,6 +20,7 @@
 //! `xcm-emulator` based tests in the cumulus folder.
 //! These tests deal with internal state changes of the XCVM.
 
+mod execute_with_origin;
 mod initiate_transfer;
 mod mock;
 mod pay_fees;
diff --git a/prdoc/pr_6304.prdoc b/prdoc/pr_6304.prdoc
new file mode 100644
index 00000000000..1c8f1bb25de
--- /dev/null
+++ b/prdoc/pr_6304.prdoc
@@ -0,0 +1,45 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: XCMv5 - Add ExecuteWithOrigin instruction
+
+doc:
+  - audience: [Runtime User, Runtime Dev]
+    description: |
+      Added a new instruction to XCMv5, ExecuteWithOrigin, that allows you to specify an interior origin
+      and a set of instructions that will be executed using that origin.
+      The origins you can choose are `None` to clear it during the execution of the inner instructions,
+      or `Some(InteriorLocation)` to descend into an interior location.
+      These two options mimic the behaviour of `ClearOrigin` and `DescendOrigin` respectively.
+      Crucially, this instruction goes back to the previous origin once the execution of those inner
+      instructions end.
+      This allows use-cases like a parent location paying fees with one interior location, fetching funds
+      with another, claiming assets on behalf of many different ones, etc.
+
+crates:
+  - name: staging-xcm
+    bump: major
+  - name: staging-xcm-executor
+    bump: minor
+  - name: staging-xcm-builder
+    bump: minor
+  - name: asset-hub-rococo-runtime
+    bump: minor
+  - name: asset-hub-westend-runtime
+    bump: minor
+  - name: bridge-hub-rococo-runtime
+    bump: minor
+  - name: bridge-hub-westend-runtime
+    bump: minor
+  - name: people-rococo-runtime
+    bump: minor
+  - name: people-westend-runtime
+    bump: minor
+  - name: coretime-rococo-runtime
+    bump: minor
+  - name: coretime-westend-runtime
+    bump: minor
+  - name: rococo-runtime
+    bump: minor
+  - name: westend-runtime
+    bump: minor
-- 
GitLab