diff --git a/Cargo.lock b/Cargo.lock
index ded2cc532933..642fe88db006 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8409,7 +8409,7 @@ dependencies = [
"pallet-minimal-template",
"polkadot-sdk-docs",
"polkadot-sdk-frame",
- "simple-mermaid",
+ "simple-mermaid 0.1.1",
]
[[package]]
@@ -13900,7 +13900,7 @@ dependencies = [
"sc-rpc-api",
"sc-service",
"scale-info",
- "simple-mermaid",
+ "simple-mermaid 0.1.1",
"sp-api",
"sp-arithmetic",
"sp-core",
@@ -18353,6 +18353,11 @@ dependencies = [
"bitflags 2.4.0",
]
+[[package]]
+name = "simple-mermaid"
+version = "0.1.0"
+source = "git+https://github.com/kianenigma/simple-mermaid.git?branch=main#e48b187bcfd5cc75111acd9d241f1bd36604344b"
+
[[package]]
name = "simple-mermaid"
version = "0.1.1"
@@ -19645,7 +19650,7 @@ dependencies = [
"scale-info",
"serde",
"serde_json",
- "simple-mermaid",
+ "simple-mermaid 0.1.1",
"sp-api",
"sp-application-crypto",
"sp-arithmetic",
@@ -21068,6 +21073,28 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+[[package]]
+name = "test-log"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93"
+dependencies = [
+ "env_logger 0.11.3",
+ "test-log-macros",
+ "tracing-subscriber 0.3.18",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5"
+dependencies = [
+ "proc-macro2 1.0.82",
+ "quote 1.0.35",
+ "syn 2.0.61",
+]
+
[[package]]
name = "test-parachain-adder"
version = "1.0.0"
@@ -23281,6 +23308,31 @@ dependencies = [
"libc",
]
+[[package]]
+name = "xcm-docs"
+version = "0.1.0"
+dependencies = [
+ "docify",
+ "pallet-balances",
+ "pallet-message-queue",
+ "pallet-xcm",
+ "parity-scale-codec",
+ "polkadot-parachain-primitives",
+ "polkadot-primitives",
+ "polkadot-runtime-parachains",
+ "polkadot-sdk-frame",
+ "scale-info",
+ "simple-mermaid 0.1.0",
+ "sp-io",
+ "sp-runtime",
+ "sp-std 14.0.0",
+ "staging-xcm",
+ "staging-xcm-builder",
+ "staging-xcm-executor",
+ "test-log",
+ "xcm-simulator",
+]
+
[[package]]
name = "xcm-emulator"
version = "0.5.0"
@@ -23379,12 +23431,16 @@ name = "xcm-simulator"
version = "7.0.0"
dependencies = [
"frame-support",
+ "frame-system",
"parity-scale-codec",
"paste",
"polkadot-core-primitives",
"polkadot-parachain-primitives",
+ "polkadot-primitives",
"polkadot-runtime-parachains",
+ "scale-info",
"sp-io",
+ "sp-runtime",
"sp-std 14.0.0",
"staging-xcm",
"staging-xcm-builder",
diff --git a/Cargo.toml b/Cargo.toml
index dcf410daa1f0..1d02b701d231 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -218,6 +218,7 @@ members = [
"polkadot/utils/generate-bags",
"polkadot/utils/remote-ext-tests/bags-list",
"polkadot/xcm",
+ "polkadot/xcm/docs",
"polkadot/xcm/pallet-xcm",
"polkadot/xcm/pallet-xcm-benchmarks",
"polkadot/xcm/procedural",
diff --git a/polkadot/xcm/docs/Cargo.toml b/polkadot/xcm/docs/Cargo.toml
new file mode 100644
index 000000000000..9820bd36dc0b
--- /dev/null
+++ b/polkadot/xcm/docs/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "xcm-docs"
+description = "Documentation and guides for XCM"
+version = "0.1.0"
+license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
+repository.workspace = true
+authors.workspace = true
+edition.workspace = true
+publish = false
+
+[dependencies]
+# For XCM stuff
+xcm = { path = "../../xcm", package = "staging-xcm" }
+xcm-executor = { path = "../../xcm/xcm-executor", package = "staging-xcm-executor" }
+xcm-builder = { path = "../../xcm/xcm-builder", package = "staging-xcm-builder" }
+xcm-simulator = { path = "../../xcm/xcm-simulator" }
+pallet-xcm = { path = "../../xcm/pallet-xcm" }
+
+# For building FRAME runtimes
+frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", features = ["experimental", "runtime"] }
+codec = { package = "parity-scale-codec", version = "3.6.9" }
+scale-info = { version = "2.6.0", default-features = false }
+polkadot-parachain-primitives = { path = "../../../polkadot/parachain" }
+polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" }
+polkadot-primitives = { path = "../../../polkadot/primitives" }
+sp-runtime = { path = "../../../substrate/primitives/runtime" }
+sp-std = { path = "../../../substrate/primitives/std" }
+sp-io = { path = "../../../substrate/primitives/io" }
+
+# Some pallets
+pallet-message-queue = { path = "../../../substrate/frame/message-queue" }
+pallet-balances = { path = "../../../substrate/frame/balances" }
+
+# For building docs
+simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" }
+docify = "0.2.6"
+
+[dev-dependencies]
+test-log = "0.2.14"
diff --git a/polkadot/xcm/docs/mermaid/location_hierarchy.mmd b/polkadot/xcm/docs/mermaid/location_hierarchy.mmd
new file mode 100644
index 000000000000..54fcfc8072a9
--- /dev/null
+++ b/polkadot/xcm/docs/mermaid/location_hierarchy.mmd
@@ -0,0 +1,9 @@
+flowchart
+ relay[Relaychain] --> paraA["Parachain(1000)"]
+ relay --> paraB["Parachain(2000)"]
+
+ paraA --> pallet[Pallet]
+ pallet --> indexA[Index 1]
+ pallet --> indexB[Index 2]
+
+ paraA --> account[Account]
diff --git a/polkadot/xcm/docs/mermaid/structure.mmd b/polkadot/xcm/docs/mermaid/structure.mmd
new file mode 100644
index 000000000000..17f60467241a
--- /dev/null
+++ b/polkadot/xcm/docs/mermaid/structure.mmd
@@ -0,0 +1,4 @@
+flowchart
+ docs[xcm_docs] --> fundamentals
+ docs --> guides
+ docs --> cookbook
diff --git a/polkadot/xcm/docs/mermaid/transport_protocols.mmd b/polkadot/xcm/docs/mermaid/transport_protocols.mmd
new file mode 100644
index 000000000000..c0340db0651a
--- /dev/null
+++ b/polkadot/xcm/docs/mermaid/transport_protocols.mmd
@@ -0,0 +1,6 @@
+flowchart
+ relay[Relaychain] --"DMP"--> paraA["Parachain(2000)"]
+ relay --"DMP"--> paraB["Parachain(2001)"]
+
+ paraA --"UMP"--> relay
+ paraB --"UMP"--> relay
diff --git a/polkadot/xcm/docs/mermaid/universal_location.mmd b/polkadot/xcm/docs/mermaid/universal_location.mmd
new file mode 100644
index 000000000000..97bfa747319d
--- /dev/null
+++ b/polkadot/xcm/docs/mermaid/universal_location.mmd
@@ -0,0 +1,3 @@
+flowchart
+ universe[Universal Location] --> polkadot[Polkadot]
+ universe --> ethereum[Ethereum]
diff --git a/polkadot/xcm/docs/mermaid/usdt_location.mmd b/polkadot/xcm/docs/mermaid/usdt_location.mmd
new file mode 100644
index 000000000000..5e9222f6098e
--- /dev/null
+++ b/polkadot/xcm/docs/mermaid/usdt_location.mmd
@@ -0,0 +1,6 @@
+flowchart
+ relay[Polkadot] --> assetHub["Asset Hub"]
+ relay --> anotherPara["Another parachain"]
+
+ assetHub --> assetsPallet["Assets Pallet"]
+ assetsPallet --> usdt[1984]
diff --git a/polkadot/xcm/docs/src/cookbook/mod.rs b/polkadot/xcm/docs/src/cookbook/mod.rs
new file mode 100644
index 000000000000..1c69bf0ead6f
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/mod.rs
@@ -0,0 +1,27 @@
+// Copyright 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 .
+
+//! # XCM Cookbook
+//!
+//! A collection of XCM recipes.
+//!
+//! Each recipe is tested and explains all the code necessary to run it -- they're not just snippets
+//! to copy and paste.
+
+/// Configuring a parachain that only uses the Relay Chain native token.
+/// In the case of Polkadot, this recipe will show you how to launch a parachain with no native
+/// token -- dealing only on DOT.
+pub mod relay_token_transactor;
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs
new file mode 100644
index 000000000000..279dd71a35f7
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs
@@ -0,0 +1,51 @@
+// Copyright 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 .
+
+//! # Relay Asset Transactor
+//!
+//! This example shows how to configure a parachain to only deal with the Relay Chain token.
+//!
+//! The first step is using the [`xcm_builder::FungibleAdapter`] to create an `AssetTransactor` that
+//! can handle the relay chain token.
+#![doc = docify::embed!("src/cookbook/relay_token_transactor/parachain/xcm_config.rs", asset_transactor)]
+//!
+//! The second step is to configure `IsReserve` to recognize the relay chain as a reserve for its
+//! own asset.
+//! With this, you'll be able to easily mint a derivative asset, backed one-to-one from the Relay
+//! Chain, by using the xcm pallet's `transfer_assets` extrinsic.
+//!
+//! The `IsReserve` type takes a type that implements `ContainsPair`.
+//! In this case, we want a type that contains the pair `(relay_chain_native_token, relay_chain)`.
+#![doc = docify::embed!("src/cookbook/relay_token_transactor/parachain/xcm_config.rs", is_reserve)]
+//!
+//! With this setup, we are able to do a reserve asset transfer to and from the parachain and relay
+//! chain.
+#![doc = docify::embed!("src/cookbook/relay_token_transactor/tests.rs", reserve_asset_transfers_work)]
+//!
+//! For the rest of the code, be sure to check the contents of this module.
+
+/// The parachain runtime for this example
+pub mod parachain;
+
+/// The relay chain runtime for this example.
+pub mod relay_chain;
+
+/// The network for this example.
+pub mod network;
+
+/// Tests for this example.
+#[cfg(test)]
+pub mod tests;
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs
new file mode 100644
index 000000000000..46ac0e5df637
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs
@@ -0,0 +1,90 @@
+// Copyright 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 .
+
+//! Mock network
+
+use frame::deps::{
+ frame_system,
+ sp_io::TestExternalities,
+ sp_runtime::{AccountId32, BuildStorage},
+};
+use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt};
+
+use super::{parachain, relay_chain};
+
+pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]);
+pub const BOB: AccountId32 = AccountId32::new([1u8; 32]);
+pub const UNITS: u64 = 10_000_000_000;
+pub const CENTS: u64 = 100_000_000;
+pub const INITIAL_BALANCE: u64 = UNITS;
+
+decl_test_parachain! {
+ pub struct ParaA {
+ Runtime = parachain::Runtime,
+ XcmpMessageHandler = parachain::MessageQueue,
+ DmpMessageHandler = parachain::MessageQueue,
+ new_ext = para_ext(),
+ }
+}
+
+decl_test_relay_chain! {
+ pub struct Relay {
+ Runtime = relay_chain::Runtime,
+ RuntimeCall = relay_chain::RuntimeCall,
+ RuntimeEvent = relay_chain::RuntimeEvent,
+ XcmConfig = relay_chain::XcmConfig,
+ MessageQueue = relay_chain::MessageQueue,
+ System = relay_chain::System,
+ new_ext = relay_ext(),
+ }
+}
+
+decl_test_network! {
+ pub struct MockNet {
+ relay_chain = Relay,
+ parachains = vec![
+ (2222, ParaA),
+ ],
+ }
+}
+
+pub fn para_ext() -> TestExternalities {
+ use parachain::{MessageQueue, Runtime, System};
+
+ let t = frame_system::GenesisConfig::::default().build_storage().unwrap();
+ let mut ext = frame::deps::sp_io::TestExternalities::new(t);
+ ext.execute_with(|| {
+ System::set_block_number(1);
+ MessageQueue::set_para_id(2222.into());
+ });
+ ext
+}
+
+pub fn relay_ext() -> TestExternalities {
+ use relay_chain::{Runtime, System};
+
+ let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();
+
+ pallet_balances::GenesisConfig:: { balances: vec![(ALICE, INITIAL_BALANCE)] }
+ .assimilate_storage(&mut t)
+ .unwrap();
+
+ let mut ext = TestExternalities::new(t);
+ ext.execute_with(|| {
+ System::set_block_number(1);
+ });
+ ext
+}
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs
new file mode 100644
index 000000000000..e3fdda2e7333
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs
@@ -0,0 +1,56 @@
+// Copyright 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 .
+
+//! # Runtime
+
+use frame::{deps::frame_system, prelude::*, runtime::prelude::*, traits::IdentityLookup};
+use xcm_executor::XcmExecutor;
+use xcm_simulator::mock_message_queue;
+
+mod xcm_config;
+use xcm_config::XcmConfig;
+
+pub type Block = frame_system::mocking::MockBlock;
+pub type AccountId = frame::deps::sp_runtime::AccountId32;
+pub type Balance = u64;
+
+construct_runtime! {
+ pub struct Runtime {
+ System: frame_system,
+ MessageQueue: mock_message_queue,
+ Balances: pallet_balances,
+ XcmPallet: pallet_xcm,
+ }
+}
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
+impl frame_system::Config for Runtime {
+ type Block = Block;
+ type AccountId = AccountId;
+ type Lookup = IdentityLookup;
+ type AccountData = pallet_balances::AccountData;
+}
+
+impl mock_message_queue::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type XcmExecutor = XcmExecutor;
+}
+
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)]
+impl pallet_balances::Config for Runtime {
+ type Balance = Balance;
+ type AccountStore = System;
+}
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs
new file mode 100644
index 000000000000..99f17693093e
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs
@@ -0,0 +1,189 @@
+// Copyright 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 .
+
+//! # XCM Configuration
+
+use frame::{
+ deps::frame_system,
+ runtime::prelude::*,
+ traits::{Everything, Nothing},
+};
+use xcm::v4::prelude::*;
+use xcm_builder::{
+ AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
+ FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete,
+ SignedToAccountId32,
+};
+use xcm_executor::XcmExecutor;
+
+use super::{AccountId, Balances, MessageQueue, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin};
+
+parameter_types! {
+ pub RelayLocation: Location = Location::parent();
+ pub ThisNetwork: NetworkId = NetworkId::Polkadot;
+}
+
+pub type LocationToAccountId = (
+ HashedDescription>,
+ AccountId32Aliases,
+);
+
+/// Configuration related to asset transactors
+#[docify::export]
+mod asset_transactor {
+ use super::*;
+
+ parameter_types! {
+ pub ParentRelayLocation: Location = Location::parent();
+ }
+
+ /// AssetTransactor for handling the relay chain token
+ pub type FungibleTransactor = FungibleAdapter<
+ // Use this implementation of the `fungible::*` traits.
+ // `Balances` is the name given to the balances pallet in this particular recipe.
+ // Any implementation of the traits would suffice.
+ Balances,
+ // This transactor deals with the native token of the Relay Chain.
+ // This token is referenced by the Location of the Relay Chain relative to this chain
+ // -- Location::parent().
+ IsConcrete,
+ // How to convert an XCM Location into a local account id.
+ // This is also something that's configured in the XCM executor.
+ LocationToAccountId,
+ // The type for account ids, only needed because `fungible` is generic over it.
+ AccountId,
+ // Not tracking teleports.
+ // This recipe only uses reserve asset transfers to handle the Relay Chain token.
+ (),
+ >;
+
+ /// Actual configuration item that'll be set in the XCM config.
+ /// A tuple could be used here to have multiple transactors, each (potentially) handling
+ /// different assets.
+ /// In this recipe, we only have one.
+ pub type AssetTransactor = FungibleTransactor;
+}
+
+/// Configuration related to token reserves
+#[docify::export]
+mod is_reserve {
+ use super::*;
+
+ parameter_types! {
+ /// Reserves are specified using a pair `(AssetFilter, Location)`.
+ /// Each pair means that the specified Location is a reserve for all the assets in AssetsFilter.
+ /// Here, we are specifying that the Relay Chain is the reserve location for its native token.
+ pub RelayTokenForRelay: (AssetFilter, Location) =
+ (Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible }), Parent.into());
+ }
+
+ /// The wrapper type xcm_builder::Case is needed in order to use this in the configuration.
+ pub type IsReserve = xcm_builder::Case;
+}
+
+mod weigher {
+ use super::*;
+ use xcm_builder::FixedWeightBounds;
+
+ parameter_types! {
+ pub const WeightPerInstruction: Weight = Weight::from_parts(1, 1);
+ pub const MaxInstructions: u32 = 100;
+ }
+
+ pub type Weigher = FixedWeightBounds;
+}
+
+parameter_types! {
+ pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Polkadot), Parachain(2222)].into();
+}
+
+pub struct XcmConfig;
+impl xcm_executor::Config for XcmConfig {
+ type RuntimeCall = RuntimeCall;
+ type XcmSender = ();
+ type AssetTransactor = asset_transactor::AssetTransactor;
+ type OriginConverter = ();
+ // The declaration of which Locations are reserves for which Assets.
+ type IsReserve = is_reserve::IsReserve;
+ type IsTeleporter = ();
+ type UniversalLocation = UniversalLocation;
+ // This is not safe, you should use `xcm_builder::AllowTopLevelPaidExecutionFrom` in a
+ // production chain
+ type Barrier = xcm_builder::AllowUnpaidExecutionFrom;
+ type Weigher = weigher::Weigher;
+ type Trader = ();
+ type ResponseHandler = ();
+ type AssetTrap = ();
+ type AssetLocker = ();
+ type AssetExchanger = ();
+ type AssetClaims = ();
+ type SubscriptionService = ();
+ type PalletInstancesInfo = ();
+ type FeeManager = ();
+ type MaxAssetsIntoHolding = frame::traits::ConstU32<1>;
+ type MessageExporter = ();
+ type UniversalAliases = Nothing;
+ type CallDispatcher = RuntimeCall;
+ type SafeCallFilter = Everything;
+ type Aliasers = Nothing;
+ type TransactionalProcessor = FrameTransactionalProcessor;
+ type HrmpNewChannelOpenRequestHandler = ();
+ type HrmpChannelAcceptedHandler = ();
+ type HrmpChannelClosingHandler = ();
+ type XcmRecorder = ();
+}
+
+pub type LocalOriginToLocation = SignedToAccountId32;
+
+impl pallet_xcm::Config for Runtime {
+ // We turn off sending for these tests
+ type SendXcmOrigin = EnsureXcmOrigin;
+ type XcmRouter = super::super::network::ParachainXcmRouter; // Provided by xcm-simulator
+ // Anyone can execute XCM programs
+ type ExecuteXcmOrigin = EnsureXcmOrigin;
+ // We execute any type of program
+ type XcmExecuteFilter = Everything;
+ // How we execute programs
+ type XcmExecutor = XcmExecutor;
+ // We don't allow teleports
+ type XcmTeleportFilter = Nothing;
+ // We allow all reserve transfers
+ type XcmReserveTransferFilter = Everything;
+ // Same weigher executor uses to weigh XCM programs
+ type Weigher = weigher::Weigher;
+ // Same universal location
+ type UniversalLocation = UniversalLocation;
+ // No version discovery needed
+ const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0;
+ type AdvertisedXcmVersion = frame::traits::ConstU32<3>;
+ type AdminOrigin = frame_system::EnsureRoot;
+ // No locking
+ type TrustedLockers = ();
+ type MaxLockers = frame::traits::ConstU32<0>;
+ type MaxRemoteLockConsumers = frame::traits::ConstU32<0>;
+ type RemoteLockConsumerIdentifier = ();
+ // How to turn locations into accounts
+ type SovereignAccountOf = LocationToAccountId;
+ // A currency to pay for things and its matcher, we are using the relay token
+ type Currency = Balances;
+ type CurrencyMatcher = IsConcrete;
+ // Pallet benchmarks, no need for this recipe
+ type WeightInfo = pallet_xcm::TestWeightInfo;
+ // Runtime types
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
+ type RuntimeEvent = RuntimeEvent;
+}
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs
new file mode 100644
index 000000000000..25c35dd4aaa8
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs
@@ -0,0 +1,103 @@
+// Copyright 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 .
+
+//! Relay chain runtime mock.
+
+use frame::{
+ deps::{frame_support::weights::WeightMeter, sp_runtime::AccountId32},
+ prelude::*,
+ runtime::prelude::*,
+ traits::{IdentityLookup, ProcessMessage, ProcessMessageError},
+};
+use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId};
+use xcm::v4::prelude::*;
+
+mod xcm_config;
+pub use xcm_config::LocationToAccountId;
+use xcm_config::XcmConfig;
+
+pub type AccountId = AccountId32;
+pub type Balance = u64;
+
+parameter_types! {
+ pub const BlockHashCount: u64 = 250;
+}
+
+#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
+impl frame_system::Config for Runtime {
+ type AccountId = AccountId;
+ type Lookup = IdentityLookup;
+ type Block = Block;
+ type AccountData = pallet_balances::AccountData;
+}
+
+#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)]
+impl pallet_balances::Config for Runtime {
+ type AccountStore = System;
+}
+
+type Block = frame_system::mocking::MockBlock;
+
+parameter_types! {
+ /// Amount of weight that can be spent per block to service messages.
+ pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
+ pub const MessageQueueHeapSize: u32 = 65_536;
+ pub const MessageQueueMaxStale: u32 = 16;
+}
+
+/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
+pub struct MessageProcessor;
+impl ProcessMessage for MessageProcessor {
+ type Origin = AggregateMessageOrigin;
+
+ fn process_message(
+ message: &[u8],
+ origin: Self::Origin,
+ meter: &mut WeightMeter,
+ id: &mut [u8; 32],
+ ) -> Result {
+ let para = match origin {
+ AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
+ };
+ xcm_builder::ProcessXcmMessage::<
+ Junction,
+ xcm_executor::XcmExecutor,
+ RuntimeCall,
+ >::process_message(message, Junction::Parachain(para.into()), meter, id)
+ }
+}
+
+impl pallet_message_queue::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type Size = u32;
+ type HeapSize = MessageQueueHeapSize;
+ type MaxStale = MessageQueueMaxStale;
+ type ServiceWeight = MessageQueueServiceWeight;
+ type MessageProcessor = MessageProcessor;
+ type QueueChangeHandler = ();
+ type QueuePausedQuery = ();
+ type WeightInfo = ();
+ type IdleMaxServiceWeight = MessageQueueServiceWeight;
+}
+
+construct_runtime! {
+ pub struct Runtime {
+ System: frame_system,
+ Balances: pallet_balances,
+ MessageQueue: pallet_message_queue,
+ XcmPallet: pallet_xcm,
+ }
+}
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs
new file mode 100644
index 000000000000..987bb3f9ab66
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs
@@ -0,0 +1,163 @@
+// Copyright 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 .
+
+//! Relay chain XCM configuration
+
+use frame::{
+ deps::frame_system,
+ runtime::prelude::*,
+ traits::{Everything, Nothing},
+};
+use xcm::v4::prelude::*;
+use xcm_builder::{
+ AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin,
+ FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete,
+ SignedToAccountId32,
+};
+use xcm_executor::XcmExecutor;
+
+use super::{AccountId, Balances, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin};
+
+parameter_types! {
+ pub HereLocation: Location = Location::here();
+ pub ThisNetwork: NetworkId = NetworkId::Polkadot;
+}
+
+/// Converter from XCM Locations to accounts.
+/// This generates sovereign accounts for Locations and converts
+/// local AccountId32 junctions to local accounts.
+pub type LocationToAccountId = (
+ HashedDescription>,
+ AccountId32Aliases,
+);
+
+mod asset_transactor {
+ use super::*;
+
+ /// AssetTransactor for handling the Relay Chain token.
+ pub type FungibleTransactor = FungibleAdapter<
+ // Use this `fungible` implementation.
+ Balances,
+ // This transactor handles the native token.
+ IsConcrete,
+ // How to convert an XCM Location into a local account id.
+ // Whenever assets are handled, the location is turned into an account.
+ // This account is the one where balances are withdrawn/deposited.
+ LocationToAccountId,
+ // The account id type, needed because `fungible` is generic over it.
+ AccountId,
+ // Not tracking teleports.
+ (),
+ >;
+
+ /// All asset transactors, in this case only one
+ pub type AssetTransactor = FungibleTransactor;
+}
+
+mod weigher {
+ use super::*;
+ use xcm_builder::FixedWeightBounds;
+
+ parameter_types! {
+ pub const WeightPerInstruction: Weight = Weight::from_parts(1, 1);
+ pub const MaxInstructions: u32 = 100;
+ }
+
+ pub type Weigher = FixedWeightBounds;
+}
+
+parameter_types! {
+ pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Polkadot)].into();
+}
+
+pub struct XcmConfig;
+impl xcm_executor::Config for XcmConfig {
+ type RuntimeCall = RuntimeCall;
+ type XcmSender = ();
+ type AssetTransactor = asset_transactor::AssetTransactor;
+ type OriginConverter = ();
+ // We don't need to recognize anyone as a reserve
+ type IsReserve = ();
+ type IsTeleporter = ();
+ type UniversalLocation = UniversalLocation;
+ // This is not safe, you should use `xcm_builder::AllowTopLevelPaidExecutionFrom` in a
+ // production chain
+ type Barrier = xcm_builder::AllowUnpaidExecutionFrom;
+ type Weigher = weigher::Weigher;
+ type Trader = ();
+ type ResponseHandler = ();
+ type AssetTrap = ();
+ type AssetLocker = ();
+ type AssetExchanger = ();
+ type AssetClaims = ();
+ type SubscriptionService = ();
+ type PalletInstancesInfo = ();
+ type FeeManager = ();
+ type MaxAssetsIntoHolding = frame::traits::ConstU32<1>;
+ type MessageExporter = ();
+ type UniversalAliases = Nothing;
+ type CallDispatcher = RuntimeCall;
+ type SafeCallFilter = Everything;
+ type Aliasers = Nothing;
+ type TransactionalProcessor = FrameTransactionalProcessor;
+ type HrmpNewChannelOpenRequestHandler = ();
+ type HrmpChannelAcceptedHandler = ();
+ type HrmpChannelClosingHandler = ();
+ type XcmRecorder = ();
+}
+
+pub type LocalOriginToLocation = SignedToAccountId32;
+
+impl pallet_xcm::Config for Runtime {
+ // No one can call `send`
+ type SendXcmOrigin = EnsureXcmOrigin;
+ type XcmRouter = super::super::network::RelayChainXcmRouter; // Provided by xcm-simulator
+ // Anyone can execute XCM programs
+ type ExecuteXcmOrigin = EnsureXcmOrigin;
+ // We execute any type of program
+ type XcmExecuteFilter = Everything;
+ // How we execute programs
+ type XcmExecutor = XcmExecutor;
+ // We don't allow teleports
+ type XcmTeleportFilter = Nothing;
+ // We allow all reserve transfers.
+ // This is so it can act as a reserve for its native token.
+ type XcmReserveTransferFilter = Everything;
+ // Same weigher executor uses to weigh XCM programs
+ type Weigher = weigher::Weigher;
+ // Same universal location
+ type UniversalLocation = UniversalLocation;
+ // No version discovery needed
+ const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0;
+ type AdvertisedXcmVersion = frame::traits::ConstU32<3>;
+ type AdminOrigin = frame_system::EnsureRoot;
+ // No locking
+ type TrustedLockers = ();
+ type MaxLockers = frame::traits::ConstU32<0>;
+ type MaxRemoteLockConsumers = frame::traits::ConstU32<0>;
+ type RemoteLockConsumerIdentifier = ();
+ // How to turn locations into accounts
+ type SovereignAccountOf = LocationToAccountId;
+ // A currency to pay for things and its matcher, we are using the relay token
+ type Currency = Balances;
+ type CurrencyMatcher = IsConcrete;
+ // Pallet benchmarks, no need for this example
+ type WeightInfo = pallet_xcm::TestWeightInfo;
+ // Runtime types
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
+ type RuntimeEvent = RuntimeEvent;
+}
diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs
new file mode 100644
index 000000000000..792cf6149e7c
--- /dev/null
+++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs
@@ -0,0 +1,128 @@
+// Copyright 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 .
+
+use frame::testing_prelude::*;
+use test_log::test;
+use xcm::prelude::*;
+use xcm_executor::traits::ConvertLocation;
+use xcm_simulator::TestExt;
+
+use super::{
+ network::{MockNet, ParaA, Relay, ALICE, BOB, CENTS, INITIAL_BALANCE},
+ parachain, relay_chain,
+};
+
+#[docify::export]
+#[test]
+fn reserve_asset_transfers_work() {
+ // Scenario:
+ // ALICE on the relay chain holds some of Relay Chain's native tokens.
+ // She transfers them to BOB's account on the parachain using a reserve transfer.
+ // BOB receives Relay Chain native token derivatives on the parachain,
+ // which are backed one-to-one with the real tokens on the Relay Chain.
+ //
+ // NOTE: We could've used ALICE on both chains because it's a different account,
+ // but using ALICE and BOB makes it clearer.
+
+ // We restart the mock network.
+ MockNet::reset();
+
+ // ALICE starts with INITIAL_BALANCE on the relay chain
+ Relay::execute_with(|| {
+ assert_eq!(relay_chain::Balances::free_balance(&ALICE), INITIAL_BALANCE);
+ });
+
+ // BOB starts with 0 on the parachain
+ ParaA::execute_with(|| {
+ assert_eq!(parachain::Balances::free_balance(&BOB), 0);
+ });
+
+ // ALICE on the Relay Chain sends some Relay Chain native tokens to BOB on the parachain.
+ // The transfer is done with the `transfer_assets` extrinsic in the XCM pallet.
+ // The extrinsic figures out it should do a reserve asset transfer
+ // with the local chain as reserve.
+ Relay::execute_with(|| {
+ // The parachain id is specified in the network.rs file in this recipe.
+ let destination: Location = Parachain(2222).into();
+ let beneficiary: Location =
+ AccountId32 { id: BOB.clone().into(), network: Some(NetworkId::Polkadot) }.into();
+ // We need to use `u128` here for the conversion to work properly.
+ // If we don't specify anything, it will be a `u64`, which the conversion
+ // will turn into a non-fungible token instead of a fungible one.
+ let assets: Assets = (Here, 50u128 * CENTS as u128).into();
+ assert_ok!(relay_chain::XcmPallet::transfer_assets(
+ relay_chain::RuntimeOrigin::signed(ALICE),
+ Box::new(VersionedLocation::V4(destination.clone())),
+ Box::new(VersionedLocation::V4(beneficiary)),
+ Box::new(VersionedAssets::V4(assets)),
+ 0,
+ WeightLimit::Unlimited,
+ ));
+
+ // ALICE now has less Relay Chain tokens.
+ assert_eq!(relay_chain::Balances::free_balance(&ALICE), INITIAL_BALANCE - 50 * CENTS);
+
+ // The funds of the sovereign account of the parachain increase by 50 cents,
+ // the ones transferred over to BOB.
+ // The funds in this sovereign account represent how many Relay Chain tokens
+ // have been sent to this parachain.
+ // If the parachain wants to send those assets somewhere else they have to go
+ // via the reserve, and this balance is updated accordingly.
+ // This is why the derivatives are backed one-to-one.
+ let parachains_sovereign_account =
+ relay_chain::LocationToAccountId::convert_location(&destination).unwrap();
+ assert_eq!(relay_chain::Balances::free_balance(parachains_sovereign_account), 50 * CENTS);
+ });
+
+ ParaA::execute_with(|| {
+ // On the parachain, BOB has received the derivative tokens
+ assert_eq!(parachain::Balances::free_balance(&BOB), 50 * CENTS);
+
+ // BOB gives back half to ALICE in the relay chain
+ let destination: Location = Parent.into();
+ let beneficiary: Location =
+ AccountId32 { id: ALICE.clone().into(), network: Some(NetworkId::Polkadot) }.into();
+ // We specify `Parent` because we are referencing the Relay Chain token.
+ // This chain doesn't have a token of its own, so we always refer to this token,
+ // and we do so by the Location of the Relay Chain.
+ let assets: Assets = (Parent, 25u128 * CENTS as u128).into();
+ assert_ok!(parachain::XcmPallet::transfer_assets(
+ parachain::RuntimeOrigin::signed(BOB),
+ Box::new(VersionedLocation::V4(destination)),
+ Box::new(VersionedLocation::V4(beneficiary)),
+ Box::new(VersionedAssets::V4(assets)),
+ 0,
+ WeightLimit::Unlimited,
+ ));
+
+ // BOB's balance decreased
+ assert_eq!(parachain::Balances::free_balance(&BOB), 25 * CENTS);
+ });
+
+ Relay::execute_with(|| {
+ // ALICE's balance increases
+ assert_eq!(
+ relay_chain::Balances::free_balance(&ALICE),
+ INITIAL_BALANCE - 50 * CENTS + 25 * CENTS
+ );
+
+ // The funds in the parachain's sovereign account decrease.
+ let parachain: Location = Parachain(2222).into();
+ let parachains_sovereign_account =
+ relay_chain::LocationToAccountId::convert_location(¶chain).unwrap();
+ assert_eq!(relay_chain::Balances::free_balance(parachains_sovereign_account), 25 * CENTS);
+ });
+}
diff --git a/polkadot/xcm/docs/src/fundamentals.rs b/polkadot/xcm/docs/src/fundamentals.rs
new file mode 100644
index 000000000000..28899df801aa
--- /dev/null
+++ b/polkadot/xcm/docs/src/fundamentals.rs
@@ -0,0 +1,177 @@
+// Copyright 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 .
+
+//! # XCM Fundamentals
+//!
+//! XCM standardizes usual actions users take in consensus systems, for example
+//! dealing with assets locally, on other chains, and locking them.
+//! XCM programs can both be executed locally or sent to a different consensus system.
+//! Examples of consensus systems are blockchains and smart contracts.
+//!
+//! The goal of XCM is to allow multi-chain ecosystems to thrive via specialization.
+//! Very specific functionalities can be abstracted away and standardized in this common language.
+//! Then, every member of the ecosystem can implement the subset of the language that makes sense
+//! for them.
+//!
+//! The language evolves over time to accomodate the needs of the community
+//! via the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md).
+//!
+//! XCM is the language, it deals with interpreting and executing programs.
+//! It does not deal with actually **sending** these programs from one consensus system to another.
+//! This responsibility falls to a transport protocol.
+//! XCM can even be interpreted on the local system, with no need of a transport protocol.
+//! However, automatic and composable workflows can be achieved via the use of one.
+//!
+//! At the core of XCM lies the XCVM, the Cross-Consensus Virtual Machine.
+//! It's the virtual machine that executes XCM programs.
+//! It is a specification that comes with the language.
+//!
+//! For these docs, we'll use a Rust implementation of XCM and the XCVM, consisting of the following
+//! parts:
+//! - [`XCM`](xcm): Holds the definition of an XCM program, the instructions and main concepts.
+//! - [`Executor`](xcm_executor): Implements the XCVM, capable of executing XCMs. Highly
+//! configurable.
+//! - [`Builder`](xcm_builder): A collection of types used to configure the executor.
+//! - [`XCM Pallet`](pallet_xcm): A FRAME pallet for interacting with the executor.
+//! - [`Simulator`](xcm_simulator): A playground to tinker with different XCM programs and executor
+//! configurations.
+//!
+//! XCM programs are composed of Instructions, which reference Locations and Assets.
+//!
+//! ## Locations
+//!
+//! Locations are XCM's vocabulary of places we want to talk about in our XCM programs.
+//! They are used to reference things like 32-byte accounts, governance bodies, smart contracts,
+//! blockchains and more.
+//!
+//! Locations are hierarchical.
+//! This means some places in consensus are wholly encapsulated in other places.
+//! Say we have two systems A and B.
+//! If any change in A's state implies a change in B's state, then we say A is interior to B.
+#![doc = simple_mermaid::mermaid!("../mermaid/location_hierarchy.mmd")]
+//!
+//! Parachains are interior to their Relay Chain, since a change in their state implies a change in
+//! the Relay Chain's state.
+//!
+//! Because of this hierarchy, the way we represent locations is with both a number of **parents**,
+//! times we move __up__ the hierarchy, and a sequence of **junctions**, the steps we take __down__
+//! the hierarchy after going up the specified number of parents.
+//!
+//! In Rust, this is specified with the following datatype:
+//! ```ignore
+//! pub struct Location {
+//! parents: u8,
+//! interior: Junctions,
+//! }
+//! ```
+//!
+//! Many junctions are available; parachains, pallets, 32 and 20 byte accounts, governance bodies,
+//! and arbitrary indices are the most common.
+//! A full list of available junctions can be found in the [format](https://github.com/paritytech/xcm-format#interior-locations--junctions)
+//! and [Junction enum](xcm::v4::prelude::Junction).
+//!
+//! We'll use a file system notation to represent locations, and start with relative locations.
+//! In the diagram, the location of parachain 1000 as seen from all other locations is as follows:
+//! - From the relaychain: `Parachain(1000)`
+//! - From parachain 1000 itself: `Here`
+//! - From parachain 2000: `../Parachain(1000)`
+//!
+//! Relative locations are interpreted by the system that is executing an XCM program, which is the
+//! receiver of a message in the case where it's sent.
+//!
+//! Locations can also be absolute.
+//! Keeping in line with our filesystem analogy, we can imagine the root of our filesystem to exist.
+//! This would be a location with no parents, that is also the parent of all systems that derive
+//! their own consensus, say Polkadot or Ethereum or Bitcoin.
+//! Such a location does not exist concretely, but we can still use this definition for it.
+//! This is the **universal location**.
+//! We need the universal location to be able to describe locations in an absolute way.
+#![doc = simple_mermaid::mermaid!("../mermaid/universal_location.mmd")]
+//!
+//! Here, the absolute location of parachain 1000 would be
+//! `GlobalConsensus(Polkadot)/Parachain(1000)`.
+//!
+//! ## Assets
+//!
+//! We want to be able to reference assets in our XCM programs, if only to be able to pay for fees.
+//! Assets are represented using locations.
+//!
+//! The native asset of a chain is represented by the location of that chain.
+//! For example, DOT is represented by the location of the Polkadot relaychain.
+//! If the interpreting chain has its own asset, it would be represented by `Here`.
+//!
+//! How do we represent other assets?
+//! The asset hub system parachain in Polkadot, for example, holds a lot of assets.
+//! To represent each of them, it uses the indices we mentioned, and it makes them interior to the
+//! assets pallet instance it uses.
+//! USDT, an example asset that lives on asset hub, is identified by the location
+//! `Parachain(1000)/PalletInstance(53)/GeneralIndex(1984)`, when seen from the Polkadot relaychain.
+#![doc = simple_mermaid::mermaid!("../mermaid/usdt_location.mmd")]
+//!
+//! Asset Hub also has another type of assets called `ForeignAssets`.
+//! These assets are identified by the XCM Location to their origin.
+//! Two such assets are a Parachain asset, like Moonbeam's GLMR, and KSM, from the cousin Kusama
+//! network. These are represented as `../Parachain(2004)/PalletInstance(10)` and
+//! `../../GlobalConsensus(Kusama)` respectively.
+//!
+//! The whole type can be seen in the [format](https://github.com/paritytech/xcm-format#6-universal-asset-identifiers)
+//! and [rust docs](xcm::v4::prelude::Asset).
+//!
+//! ## Instructions
+//!
+//! Given the vocabulary to talk about both locations -- chains and accounts -- and assets, we now
+//! need a way to express what we want the consensus system to do when executing our programs.
+//! We need a way of writing our programs.
+//!
+//! XCM programs are composed of a sequence of instructions.
+//!
+//! All available instructions can be seen in the [format](https://github.com/paritytech/xcm-format#5-the-xcvm-instruction-set)
+//! and the [Instruction enum](xcm::v4::prelude::Instruction).
+//!
+//! A very simple example is the following:
+//!
+//! ```ignore
+//! let message = Xcm(vec![
+//! TransferAsset { assets, beneficiary },
+//! ]);
+//! ```
+//!
+//! This instruction is enough to transfer `assets` from the account of the **origin** of a message
+//! to the `beneficiary` account. However, because of XCM's generality, fees need to be paid
+//! explicitly. This next example sheds more light on this:
+//!
+//! ```ignore
+//! let message = Xcm(vec![
+//! WithdrawAsset(assets),
+//! BuyExecution { fees: assets, weight_limit },
+//! DepositAsset { assets: AssetFilter(Wild(All)), beneficiary },
+//! ]);
+//! ```
+//!
+//! Here we see the process of transferring assets was broken down into smaller instructions, and we
+//! add the explicit fee payment step in the middle.
+//! `WithdrawAsset` withdraws assets from the account of the **origin** of the message for usage
+//! inside this message's execution. `BuyExecution` explicitly buys execution for this program using
+//! the assets specified in `fees`, with a sanity check of `weight_limit`. `DepositAsset` uses a
+//! wildcard, specifying all remaining `assets` after subtracting the fees and a `beneficiary`
+//! account.
+//!
+//! ## Next steps
+//!
+//! Continue with the [guides](crate::guides) for step-by-step tutorials on XCM,
+//! or jump to the [cookbook](crate::cookbook) to see examples.
+//!
+//! The [glossary](crate::glossary) can be useful if some of the terms are confusing.
diff --git a/polkadot/xcm/docs/src/glossary.rs b/polkadot/xcm/docs/src/glossary.rs
new file mode 100644
index 000000000000..6035888ab733
--- /dev/null
+++ b/polkadot/xcm/docs/src/glossary.rs
@@ -0,0 +1,123 @@
+// Copyright 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 .
+
+//! # Glossary
+//!
+//! ## XCM (Cross-Consensus Messaging)
+//!
+//! A messaging format meant to communicate intentions between consensus systems.
+//! XCM could also refer to a single message.
+//!
+//! ## Instructions
+//!
+//! XCMs are composed of a sequence of instructions.
+//! Each instruction aims to convey a particular intention.
+//! There are instructions for transferring and locking assets, handling fees, calling arbitrary
+//! blobs, and more.
+//!
+//! ## Consensus system
+//!
+//! A system that can reach any kind of consensus.
+//! For example, relay chains, parachains, smart contracts.
+//! Most messaging between consensus systems has to be done asynchronously, for this, XCM is used.
+//! Between two smart contracts on the same parachain, however, communication can be done
+//! synchronously.
+//!
+//! ## [`Location`](xcm::v4::prelude::Location)
+//!
+//! A way of addressing consensus systems.
+//! These could be relative or absolute.
+//!
+//! ## [`Junction`](xcm::v4::prelude::Junction)
+//!
+//! The different ways of descending down a [`Location`](xcm::v4::prelude::Location) hierarchy.
+//! A junction can be a Parachain, an Account, or more.
+//!
+//! ## [`Asset`](xcm::v4::prelude::Asset)
+//!
+//! A way of identifying assets in the same or another consensus system, by using a
+//! [`Location`](xcm::v4::prelude::Location).
+//!
+//! ## Sovereign account
+//!
+//! An account in a consensus system that is controlled by an account in another consensus system.
+//!
+//! Runtimes use a converter between a [`Location`](xcm::v4::prelude::Location) and an account.
+//! These converters implement the [`ConvertLocation`](xcm_executor::traits::ConvertLocation) trait.
+//!
+//! ## Teleport
+//!
+//! A way of transferring assets between two consensus systems without the need of a third party.
+//! It consists of the sender system burning the asset that wants to be sent over and the recipient
+//! minting an equivalent amount of that asset. It requires a lot of trust between the two systems,
+//! since failure to mint or burn will reduce or increase the total issuance of the token.
+//!
+//! ## Reserve asset transfer
+//!
+//! A way of transferring assets between two consensus systems that don't trust each other, by using
+//! a third system they both trust, called the reserve. The real asset only exists on the reserve,
+//! both sender and recipient only deal with derivatives. It consists of the sender burning a
+//! certain amount of derivatives, telling the reserve to move real assets from its sovereign
+//! account to the destination's sovereign account, and then telling the recipient to mint the right
+//! amount of derivatives.
+//! In practice, the reserve chain can also be one of the source or destination.
+//!
+//! ## XCVM
+//!
+//! The virtual machine behind XCM.
+//! Every XCM is an XCVM programme.
+//! Holds state in registers.
+//!
+//! An implementation of the virtual machine is the [`xcm-executor`](xcm_executor::XcmExecutor).
+//!
+//! ## Holding register
+//!
+//! An XCVM register used to hold arbitrary `Asset`s during the execution of an XCVM programme.
+//!
+//! ## Barrier
+//!
+//! An XCM executor configuration item that works as a firewall for incoming XCMs.
+//! All XCMs have to pass the barrier to be executed, else they are dropped.
+//! It can be used for whitelisting only certain types or messages or messages from certain senders.
+//!
+//! Lots of barrier definitions exist in [`xcm-builder`](xcm_builder).
+//!
+//! ## VMP (Vertical Message Passing)
+//!
+//! Umbrella term for both UMP (Upward Message Passing) and DMP (Downward Message Passing).
+//!
+//! The following diagram shows the uses of both protocols:
+#![doc = simple_mermaid::mermaid!("../mermaid/transport_protocols.mmd")]
+//!
+//! ## UMP (Upward Message Passing)
+//!
+//! Transport-layer protocol that allows parachains to send messages upwards to their relay chain.
+//!
+//! ## DMP (Downward Message Passing)
+//!
+//! Transport-layer protocol that allows the relay chain to send messages downwards to one of their
+//! parachains.
+//!
+//! ## XCMP (Cross-Consensus Message Passing)
+//!
+//! Transport-layer protocol that allows parachains to send messages between themselves, without
+//! going through the relay chain.
+//!
+//! ## HRMP (Horizontal Message Passing)
+//!
+//! Transport-layer protocol that allows a parachain to send messages to a sibling parachain going
+//! through the relay chain. It's a precursor to XCMP, also known as XCMP-lite.
+//! It uses a mixture of UMP and DMP.
diff --git a/polkadot/xcm/docs/src/guides/mod.rs b/polkadot/xcm/docs/src/guides/mod.rs
new file mode 100644
index 000000000000..5af89428d9a4
--- /dev/null
+++ b/polkadot/xcm/docs/src/guides/mod.rs
@@ -0,0 +1,25 @@
+// Copyright 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 .
+
+//! # XCM Guides
+//!
+//! These guides aim to get you up and running with XCM.
+//!
+//! Coming soon.
+//!
+//! ## Next steps
+//!
+//! Jump to the [cookbook](crate::cookbook) for different examples.
diff --git a/polkadot/xcm/docs/src/lib.rs b/polkadot/xcm/docs/src/lib.rs
new file mode 100644
index 000000000000..287c97140c91
--- /dev/null
+++ b/polkadot/xcm/docs/src/lib.rs
@@ -0,0 +1,63 @@
+// Copyright 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 .
+
+//! # XCM Docs
+//!
+//! Documentation and guides for XCM
+//!
+//! Welcome to the Cross-Consensus Messaging documentation!
+//!
+//! XCM is a **language** for communicating **intentions** between **consensus systems**.
+//! Whether you're a developer, a blockchain enthusiast, or just interested in Polkadot, this guide
+//! aims to provide you with an easy-to-understand and comprehensive introduction to XCM.
+//!
+//! ## Getting started
+//!
+//! Head over to the [fundamentals](fundamentals) section.
+//! Then, go to the [guides](guides), to learn about how to do things with XCM.
+//!
+//! ## Cookbook
+//!
+//! There's also the [cookbook](cookbook) for useful recipes for XCM.
+//!
+//! ## Glossary
+//!
+//! There's a [glossary](glossary) with common terms used throughout the docs.
+//!
+//! ## Contribute
+//!
+//! To contribute to the format, check out the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md).
+//! To contribute to these docs, [make a PR](https://github.com/paritytech/polkadot-sdk).
+//!
+//! ## Why Rust Docs?
+//!
+//! Rust Docs allow docs to be as close to the source as possible.
+//! They're also available offline automatically for anyone who has the `polkadot-sdk` repo locally.
+//!
+//! ## Docs structure
+#![doc = simple_mermaid::mermaid!("../mermaid/structure.mmd")]
+
+/// Fundamentals of the XCM language. The virtual machine, instructions, locations and assets.
+pub mod fundamentals;
+
+/// Step-by-step guides to set up an XCM environment and start hacking.
+pub mod guides;
+
+/// Useful recipes for programs and configurations.
+pub mod cookbook;
+
+/// Glossary
+pub mod glossary;
diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml
index 9324359d365d..fc09b5e31861 100644
--- a/polkadot/xcm/xcm-simulator/Cargo.toml
+++ b/polkadot/xcm/xcm-simulator/Cargo.toml
@@ -11,15 +11,19 @@ workspace = true
[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.12" }
+scale-info = { version = "2.6.0", default-features = false }
paste = "1.0.7"
frame-support = { path = "../../../substrate/frame/support" }
+frame-system = { path = "../../../substrate/frame/system" }
sp-io = { path = "../../../substrate/primitives/io" }
sp-std = { path = "../../../substrate/primitives/std" }
+sp-runtime = { path = "../../../substrate/primitives/runtime" }
xcm = { package = "staging-xcm", path = ".." }
xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor" }
xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" }
+polkadot-primitives = { path = "../../primitives" }
polkadot-core-primitives = { path = "../../core-primitives" }
polkadot-parachain-primitives = { path = "../../parachain" }
polkadot-runtime-parachains = { path = "../../runtime/parachains" }
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
index 8021f9551658..93c8302757cb 100644
--- a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
@@ -16,7 +16,6 @@
//! Parachain runtime mock.
-mod mock_msg_queue;
mod xcm_config;
pub use xcm_config::*;
@@ -36,6 +35,7 @@ use sp_std::prelude::*;
use xcm::latest::prelude::*;
use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32};
use xcm_executor::{traits::ConvertLocation, XcmExecutor};
+use xcm_simulator::mock_message_queue;
pub type AccountId = AccountId32;
pub type Balance = u128;
@@ -121,7 +121,7 @@ parameter_types! {
pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
}
-impl mock_msg_queue::Config for Runtime {
+impl mock_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor;
}
@@ -175,7 +175,7 @@ construct_runtime!(
pub struct Runtime {
System: frame_system,
Balances: pallet_balances,
- MsgQueue: mock_msg_queue,
+ MsgQueue: mock_message_queue,
PolkadotXcm: pallet_xcm,
ForeignUniques: pallet_uniques,
}
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
index f6d0174def8f..0769507ec37b 100644
--- a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs
@@ -14,9 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
-use crate::parachain::MsgQueue;
+use crate::parachain::Runtime;
use frame_support::parameter_types;
use xcm::latest::prelude::*;
+use xcm_simulator::mock_message_queue::ParachainId;
parameter_types! {
pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1);
@@ -26,5 +27,5 @@ parameter_types! {
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 UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainId::::get().into())].into();
}
diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs
index 6486a849af36..34c1feb6e946 100644
--- a/polkadot/xcm/xcm-simulator/example/src/tests.rs
+++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs
@@ -19,7 +19,7 @@ use crate::*;
use codec::Encode;
use frame_support::{assert_ok, weights::Weight};
use xcm::latest::QueryResponseInfo;
-use xcm_simulator::TestExt;
+use xcm_simulator::{mock_message_queue::ReceivedDmp, TestExt};
// Helper function for forming buy execution message
fn buy_execution(fees: impl Into) -> Instruction {
@@ -171,7 +171,7 @@ fn remote_locking_and_unlocking() {
ParaA::execute_with(|| {
assert_eq!(
- parachain::MsgQueue::received_dmp(),
+ ReceivedDmp::::get(),
vec![Xcm(vec![NoteUnlockable {
owner: (Parent, Parachain(2)).into(),
asset: (Parent, locked_amount).into()
@@ -501,7 +501,7 @@ fn query_holding() {
// Check that QueryResponse message was received
ParaA::execute_with(|| {
assert_eq!(
- parachain::MsgQueue::received_dmp(),
+ ReceivedDmp::::get(),
vec![Xcm(vec![QueryResponse {
query_id: query_id_set,
response: Response::Assets(Assets::new()),
diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs
index 7efbc658bbfb..a6747a4789ed 100644
--- a/polkadot/xcm/xcm-simulator/src/lib.rs
+++ b/polkadot/xcm/xcm-simulator/src/lib.rs
@@ -16,6 +16,10 @@
//! Test kit to simulate cross-chain message passing and XCM execution.
+/// Implementation of a simple message queue.
+/// Used for sending messages.
+pub mod mock_message_queue;
+
pub use codec::Encode;
pub use paste;
diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs
similarity index 72%
rename from polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
rename to polkadot/xcm/xcm-simulator/src/mock_message_queue.rs
index 17cde921f3e2..96b47999fe95 100644
--- a/polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
+++ b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs
@@ -1,4 +1,4 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
+// Copyright Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
@@ -14,14 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
-pub use pallet::*;
-use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
+//! Simple mock message queue.
+
+use codec::{Decode, Encode};
+
use polkadot_parachain_primitives::primitives::{
DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler,
};
+use polkadot_primitives::BlockNumber as RelayBlockNumber;
use sp_runtime::traits::{Get, Hash};
+
+use sp_std::prelude::*;
use xcm::{latest::prelude::*, VersionedXcm};
+pub use pallet::*;
+
#[frame_support::pallet]
pub mod pallet {
use super::*;
@@ -41,15 +48,15 @@ pub mod pallet {
pub struct Pallet(_);
#[pallet::storage]
- pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>;
+ pub type ParachainId = StorageValue<_, ParaId, ValueQuery>;
#[pallet::storage]
/// A queue of received DMP messages
- pub(super) type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>;
+ pub type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>;
impl Get for Pallet {
fn get() -> ParaId {
- Self::parachain_id()
+ ParachainId::::get()
}
}
@@ -60,45 +67,34 @@ pub mod pallet {
pub enum Event {
// XCMP
/// Some XCM was executed OK.
- Success(Option),
+ Success { message_id: Option },
/// Some XCM failed.
- Fail(Option, XcmError),
+ Fail { message_id: Option, error: XcmError },
/// Bad XCM version used.
- BadVersion(Option),
+ BadVersion { message_id: Option },
/// Bad XCM format used.
- BadFormat(Option),
+ BadFormat { message_id: Option },
// DMP
/// Downward message is invalid XCM.
- InvalidFormat(MessageId),
+ InvalidFormat { message_id: MessageId },
/// Downward message is unsupported version of XCM.
- UnsupportedVersion(MessageId),
+ UnsupportedVersion { message_id: MessageId },
/// Downward message executed with the given outcome.
- ExecutedDownward(MessageId, Outcome),
+ ExecutedDownward { message_id: MessageId, outcome: Outcome },
}
impl Pallet {
- /// Get the Parachain Id.
- pub fn parachain_id() -> ParaId {
- ParachainId::::get()
- }
-
- /// Set the Parachain Id.
pub fn set_para_id(para_id: ParaId) {
ParachainId::::put(para_id);
}
- /// Get the queue of receieved DMP messages.
- pub fn received_dmp() -> Vec> {
- ReceivedDmp::::get()
- }
-
fn handle_xcmp_message(
sender: ParaId,
_sent_at: RelayBlockNumber,
xcm: VersionedXcm,
- max_weight: Weight,
- ) -> Result {
+ max_weight: xcm::latest::Weight,
+ ) -> Result {
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::::try_from(xcm) {
@@ -111,15 +107,20 @@ pub mod pallet {
max_weight,
Weight::zero(),
) {
- Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)),
- Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))),
+ Outcome::Error { error } =>
+ (Err(error), Event::Fail { message_id: Some(hash), error }),
+ Outcome::Complete { used } =>
+ (Ok(used), Event::Success { message_id: 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)),
+ (Ok(used), Event::Fail { message_id: Some(hash), error }),
}
},
- Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
+ Err(()) => (
+ Err(XcmError::UnhandledXcmVersion),
+ Event::BadVersion { message_id: Some(hash) },
+ ),
};
Self::deposit_event(event);
result
@@ -129,8 +130,8 @@ pub mod pallet {
impl XcmpMessageHandler for Pallet {
fn handle_xcmp_messages<'a, I: Iterator- >(
iter: I,
- max_weight: Weight,
- ) -> Weight {
+ max_weight: xcm::latest::Weight,
+ ) -> xcm::latest::Weight {
for (sender, sent_at, data) in iter {
let mut data_ref = data;
let _ = XcmpMessageFormat::decode(&mut data_ref)
@@ -156,15 +157,16 @@ pub mod pallet {
iter: impl Iterator
- )>,
limit: Weight,
) -> Weight {
- for (_i, (_sent_at, data)) in iter.enumerate() {
+ for (_sent_at, data) in iter {
let mut id = sp_io::hashing::blake2_256(&data[..]);
let maybe_versioned = VersionedXcm::::decode(&mut &data[..]);
match maybe_versioned {
Err(_) => {
- Self::deposit_event(Event::InvalidFormat(id));
+ Self::deposit_event(Event::InvalidFormat { message_id: id });
},
Ok(versioned) => match Xcm::try_from(versioned) {
- Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
+ Err(()) =>
+ Self::deposit_event(Event::UnsupportedVersion { message_id: id }),
Ok(x) => {
let outcome = T::XcmExecutor::prepare_and_execute(
Parent,
@@ -173,8 +175,11 @@ pub mod pallet {
limit,
Weight::zero(),
);
- >::append(x);
- Self::deposit_event(Event::ExecutedDownward(id, outcome));
+ ReceivedDmp::::append(x);
+ Self::deposit_event(Event::ExecutedDownward {
+ message_id: id,
+ outcome,
+ });
},
},
}