staging_xcm/v2/
mod.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! # XCM Version 2
18//!
19//! WARNING: DEPRECATED, please use version 3 or 4.
20//!
21//! Version 2 of the Cross-Consensus Message format data structures. The comprehensive list of
22//! changes can be found in
23//! [this PR description](https://github.com/paritytech/polkadot/pull/3629#issue-968428279).
24//!
25//! ## Changes to be aware of
26//! The biggest change here is the restructuring of XCM messages: instead of having `Order` and
27//! `Xcm` types, the `Xcm` type now simply wraps a `Vec` containing `Instruction`s. However, most
28//! changes should still be automatically convertible via the `try_from` and `from` conversion
29//! functions.
30//!
31//! ### Junction
32//! - No special attention necessary
33//!
34//! ### `MultiLocation`
35//! - No special attention necessary
36//!
37//! ### `MultiAsset`
38//! - No special attention necessary
39//!
40//! ### XCM and Order
41//! - `Xcm` and `Order` variants are now combined under a single `Instruction` enum.
42//! - `Order` is now obsolete and replaced entirely by `Instruction`.
43//! - `Xcm` is now a simple wrapper around a `Vec<Instruction>`.
44//! - During conversion from `Order` to `Instruction`, we do not handle `BuyExecution`s that have
45//!   nested XCMs, i.e. if the `instructions` field in the `BuyExecution` enum struct variant is not
46//!   empty, then the conversion will fail. To address this, rewrite the XCM using `Instruction`s in
47//!   chronological order.
48//! - During conversion from `Xcm` to `Instruction`, we do not handle `RelayedFrom` messages at all.
49//!
50//! ### XCM Pallet
51//! - The `Weigher` configuration item must have sensible weights defined for `BuyExecution` and
52//!   `DepositAsset` instructions. Failing that, dispatch calls to `teleport_assets` and
53//!   `reserve_transfer_assets` will fail with `UnweighableMessage`.
54
55use super::{
56	v3::{
57		BodyId as NewBodyId, BodyPart as NewBodyPart, Instruction as NewInstruction,
58		NetworkId as NewNetworkId, OriginKind as NewOriginKind, Response as NewResponse,
59		WeightLimit as NewWeightLimit, Xcm as NewXcm,
60	},
61	DoubleEncoded,
62};
63use alloc::{vec, vec::Vec};
64use bounded_collections::{ConstU32, WeakBoundedVec};
65use codec::{
66	self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput,
67	MaxEncodedLen,
68};
69use core::{fmt::Debug, result};
70use derivative::Derivative;
71use scale_info::TypeInfo;
72
73mod junction;
74mod multiasset;
75mod multilocation;
76mod traits;
77
78pub use junction::Junction;
79pub use multiasset::{
80	AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
81	WildFungibility, WildMultiAsset,
82};
83pub use multilocation::{
84	Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen,
85};
86pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendResult, SendXcm};
87
88/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
89#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
90#[scale_info(replace_segment("staging_xcm", "xcm"))]
91#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
92pub enum OriginKind {
93	/// Origin should just be the native dispatch origin representation for the sender in the
94	/// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
95	/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
96	/// primary/native dispatch origin form.
97	Native,
98
99	/// Origin should just be the standard account-based origin with the sovereign account of
100	/// the sender. For Cumulus/Frame chains, this is the `Signed` origin.
101	SovereignAccount,
102
103	/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
104	/// This will not usually be an available option.
105	Superuser,
106
107	/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
108	/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
109	/// the `pallet_xcm::Origin::Xcm` type.
110	Xcm,
111}
112
113impl From<NewOriginKind> for OriginKind {
114	fn from(new: NewOriginKind) -> Self {
115		use NewOriginKind::*;
116		match new {
117			Native => Self::Native,
118			SovereignAccount => Self::SovereignAccount,
119			Superuser => Self::Superuser,
120			Xcm => Self::Xcm,
121		}
122	}
123}
124
125/// A global identifier of an account-bearing consensus system.
126#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
127#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
128#[scale_info(replace_segment("staging_xcm", "xcm"))]
129pub enum NetworkId {
130	/// Unidentified/any.
131	Any,
132	/// Some named network.
133	Named(WeakBoundedVec<u8, ConstU32<32>>),
134	/// The Polkadot Relay chain
135	Polkadot,
136	/// Kusama.
137	Kusama,
138}
139
140impl TryFrom<Option<NewNetworkId>> for NetworkId {
141	type Error = ();
142	fn try_from(new: Option<NewNetworkId>) -> result::Result<NetworkId, ()> {
143		match new {
144			None => Ok(NetworkId::Any),
145			Some(id) => Self::try_from(id),
146		}
147	}
148}
149
150impl TryFrom<NewNetworkId> for NetworkId {
151	type Error = ();
152	fn try_from(new: NewNetworkId) -> result::Result<NetworkId, ()> {
153		use NewNetworkId::*;
154		match new {
155			Polkadot => Ok(NetworkId::Polkadot),
156			Kusama => Ok(NetworkId::Kusama),
157			_ => Err(()),
158		}
159	}
160}
161
162/// An identifier of a pluralistic body.
163#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
164#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
165#[scale_info(replace_segment("staging_xcm", "xcm"))]
166pub enum BodyId {
167	/// The only body in its context.
168	Unit,
169	/// A named body.
170	Named(WeakBoundedVec<u8, ConstU32<32>>),
171	/// An indexed body.
172	Index(#[codec(compact)] u32),
173	/// The unambiguous executive body (for Polkadot, this would be the Polkadot council).
174	Executive,
175	/// The unambiguous technical body (for Polkadot, this would be the Technical Committee).
176	Technical,
177	/// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a
178	/// majority of lock-voters).
179	Legislative,
180	/// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a
181	/// "grand oracle", it may be considered as that).
182	Judicial,
183	/// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public
184	/// referendum on the `staking_admin` track).
185	Defense,
186	/// The unambiguous administration body (for Polkadot, an opinion on the topic given via a
187	/// public referendum on the `general_admin` track).
188	Administration,
189	/// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public
190	/// referendum on the `treasurer` track).
191	Treasury,
192}
193
194impl From<NewBodyId> for BodyId {
195	fn from(n: NewBodyId) -> Self {
196		use NewBodyId::*;
197		match n {
198			Unit => Self::Unit,
199			Moniker(n) => Self::Named(
200				n[..]
201					.to_vec()
202					.try_into()
203					.expect("array size is 4 and so will never be out of bounds; qed"),
204			),
205			Index(n) => Self::Index(n),
206			Executive => Self::Executive,
207			Technical => Self::Technical,
208			Legislative => Self::Legislative,
209			Judicial => Self::Judicial,
210			Defense => Self::Defense,
211			Administration => Self::Administration,
212			Treasury => Self::Treasury,
213		}
214	}
215}
216
217/// A part of a pluralistic body.
218#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
219#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
220#[scale_info(replace_segment("staging_xcm", "xcm"))]
221pub enum BodyPart {
222	/// The body's declaration, under whatever means it decides.
223	Voice,
224	/// A given number of members of the body.
225	Members {
226		#[codec(compact)]
227		count: u32,
228	},
229	/// A given number of members of the body, out of some larger caucus.
230	Fraction {
231		#[codec(compact)]
232		nom: u32,
233		#[codec(compact)]
234		denom: u32,
235	},
236	/// No less than the given proportion of members of the body.
237	AtLeastProportion {
238		#[codec(compact)]
239		nom: u32,
240		#[codec(compact)]
241		denom: u32,
242	},
243	/// More than the given proportion of members of the body.
244	MoreThanProportion {
245		#[codec(compact)]
246		nom: u32,
247		#[codec(compact)]
248		denom: u32,
249	},
250}
251
252impl BodyPart {
253	/// Returns `true` if the part represents a strict majority (> 50%) of the body in question.
254	pub fn is_majority(&self) -> bool {
255		match self {
256			BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true,
257			BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true,
258			BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true,
259			_ => false,
260		}
261	}
262}
263
264impl From<NewBodyPart> for BodyPart {
265	fn from(n: NewBodyPart) -> Self {
266		use NewBodyPart::*;
267		match n {
268			Voice => Self::Voice,
269			Members { count } => Self::Members { count },
270			Fraction { nom, denom } => Self::Fraction { nom, denom },
271			AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom },
272			MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom },
273		}
274	}
275}
276
277/// This module's XCM version.
278pub const VERSION: super::Version = 2;
279
280/// An identifier for a query.
281pub type QueryId = u64;
282
283/// DEPRECATED. Please use XCMv3 or XCMv4 instead.
284#[derive(Derivative, Default, Encode, TypeInfo)]
285#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
286#[codec(encode_bound())]
287#[codec(decode_bound())]
288#[scale_info(bounds(), skip_type_params(RuntimeCall))]
289#[scale_info(replace_segment("staging_xcm", "xcm"))]
290pub struct Xcm<RuntimeCall>(pub Vec<Instruction<RuntimeCall>>);
291
292environmental::environmental!(instructions_count: u8);
293
294impl<Call> Decode for Xcm<Call> {
295	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
296		instructions_count::using_once(&mut 0, || {
297			let number_of_instructions: u32 = <Compact<u32>>::decode(input)?.into();
298			instructions_count::with(|count| {
299				*count = count.saturating_add(number_of_instructions as u8);
300				if *count > MAX_INSTRUCTIONS_TO_DECODE {
301					return Err(CodecError::from("Max instructions exceeded"))
302				}
303				Ok(())
304			})
305			.unwrap_or(Ok(()))?;
306			let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?;
307			Ok(Self(decoded_instructions))
308		})
309	}
310}
311
312/// The maximal number of instructions in an XCM before decoding fails.
313///
314/// This is a deliberate limit - not a technical one.
315pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100;
316
317impl<RuntimeCall> Xcm<RuntimeCall> {
318	/// Create an empty instance.
319	pub fn new() -> Self {
320		Self(vec![])
321	}
322
323	/// Return `true` if no instructions are held in `self`.
324	pub fn is_empty(&self) -> bool {
325		self.0.is_empty()
326	}
327
328	/// Return the number of instructions held in `self`.
329	pub fn len(&self) -> usize {
330		self.0.len()
331	}
332
333	/// Consume and either return `self` if it contains some instructions, or if it's empty, then
334	/// instead return the result of `f`.
335	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
336		if self.0.is_empty() {
337			f()
338		} else {
339			self
340		}
341	}
342
343	/// Return the first instruction, if any.
344	pub fn first(&self) -> Option<&Instruction<RuntimeCall>> {
345		self.0.first()
346	}
347
348	/// Return the last instruction, if any.
349	pub fn last(&self) -> Option<&Instruction<RuntimeCall>> {
350		self.0.last()
351	}
352
353	/// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise).
354	pub fn only(&self) -> Option<&Instruction<RuntimeCall>> {
355		if self.0.len() == 1 {
356			self.0.first()
357		} else {
358			None
359		}
360	}
361
362	/// Return the only instruction, contained in `Self`, iff only one exists (returns `self`
363	/// otherwise).
364	pub fn into_only(mut self) -> core::result::Result<Instruction<RuntimeCall>, Self> {
365		if self.0.len() == 1 {
366			self.0.pop().ok_or(self)
367		} else {
368			Err(self)
369		}
370	}
371}
372
373/// A prelude for importing all types typically used when interacting with XCM messages.
374pub mod prelude {
375	mod contents {
376		pub use super::super::{
377			Ancestor, AncestorThen,
378			AssetId::{self, *},
379			AssetInstance::{self, *},
380			BodyId, BodyPart, Error as XcmError, ExecuteXcm,
381			Fungibility::{self, *},
382			Instruction::*,
383			InteriorMultiLocation,
384			Junction::{self, *},
385			Junctions::{self, *},
386			MultiAsset,
387			MultiAssetFilter::{self, *},
388			MultiAssets, MultiLocation,
389			NetworkId::{self, *},
390			OriginKind, Outcome, Parent, ParentThen, QueryId, Response, Result as XcmResult,
391			SendError, SendResult, SendXcm,
392			WeightLimit::{self, *},
393			WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
394			WildMultiAsset::{self, *},
395			XcmWeightInfo, VERSION as XCM_VERSION,
396		};
397	}
398	pub use super::{Instruction, Xcm};
399	pub use contents::*;
400	pub mod opaque {
401		pub use super::{
402			super::opaque::{Instruction, Xcm},
403			contents::*,
404		};
405	}
406}
407
408/// Response data to a query.
409#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
410#[scale_info(replace_segment("staging_xcm", "xcm"))]
411pub enum Response {
412	/// No response. Serves as a neutral default.
413	Null,
414	/// Some assets.
415	Assets(MultiAssets),
416	/// The outcome of an XCM instruction.
417	ExecutionResult(Option<(u32, Error)>),
418	/// An XCM version.
419	Version(super::Version),
420}
421
422impl Default for Response {
423	fn default() -> Self {
424		Self::Null
425	}
426}
427
428/// An optional weight limit.
429#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
430#[scale_info(replace_segment("staging_xcm", "xcm"))]
431pub enum WeightLimit {
432	/// No weight limit imposed.
433	Unlimited,
434	/// Weight limit imposed of the inner value.
435	Limited(#[codec(compact)] u64),
436}
437
438impl From<Option<u64>> for WeightLimit {
439	fn from(x: Option<u64>) -> Self {
440		match x {
441			Some(w) => WeightLimit::Limited(w),
442			None => WeightLimit::Unlimited,
443		}
444	}
445}
446
447impl From<WeightLimit> for Option<u64> {
448	fn from(x: WeightLimit) -> Self {
449		match x {
450			WeightLimit::Limited(w) => Some(w),
451			WeightLimit::Unlimited => None,
452		}
453	}
454}
455
456impl TryFrom<NewWeightLimit> for WeightLimit {
457	type Error = ();
458	fn try_from(x: NewWeightLimit) -> result::Result<Self, Self::Error> {
459		use NewWeightLimit::*;
460		match x {
461			Limited(w) => Ok(Self::Limited(w.ref_time())),
462			Unlimited => Ok(Self::Unlimited),
463		}
464	}
465}
466
467/// Local weight type; execution time in picoseconds.
468pub type Weight = u64;
469
470/// Cross-Consensus Message: A message from one consensus system to another.
471///
472/// Consensus systems that may send and receive messages include blockchains and smart contracts.
473///
474/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`.
475///
476/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the
477/// outer XCM format, known as `VersionedXcm`.
478#[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)]
479#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
480#[codec(encode_bound())]
481#[codec(decode_bound())]
482#[scale_info(bounds(), skip_type_params(RuntimeCall))]
483#[scale_info(replace_segment("staging_xcm", "xcm"))]
484pub enum Instruction<RuntimeCall> {
485	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding
486	/// Register.
487	///
488	/// - `assets`: The asset(s) to be withdrawn into holding.
489	///
490	/// Kind: *Command*.
491	///
492	/// Errors:
493	WithdrawAsset(MultiAssets),
494
495	/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin`
496	/// system and equivalent derivatives should be placed into the Holding Register.
497	///
498	/// - `assets`: The asset(s) that are minted into holding.
499	///
500	/// Safety: `origin` must be trusted to have received and be storing `assets` such that they
501	/// may later be withdrawn should this system send a corresponding message.
502	///
503	/// Kind: *Trusted Indication*.
504	///
505	/// Errors:
506	ReserveAssetDeposited(MultiAssets),
507
508	/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should
509	/// be created and placed into the Holding Register.
510	///
511	/// - `assets`: The asset(s) that are minted into the Holding Register.
512	///
513	/// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets`
514	/// prior as a consequence of sending this message.
515	///
516	/// Kind: *Trusted Indication*.
517	///
518	/// Errors:
519	ReceiveTeleportedAsset(MultiAssets),
520
521	/// Respond with information that the local system is expecting.
522	///
523	/// - `query_id`: The identifier of the query that resulted in this message being sent.
524	/// - `response`: The message content.
525	/// - `max_weight`: The maximum weight that handling this response should take.
526	///
527	/// Safety: No concerns.
528	///
529	/// Kind: *Information*.
530	///
531	/// Errors:
532	QueryResponse {
533		#[codec(compact)]
534		query_id: QueryId,
535		response: Response,
536		#[codec(compact)]
537		max_weight: u64,
538	},
539
540	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
541	/// under the ownership of `beneficiary`.
542	///
543	/// - `assets`: The asset(s) to be withdrawn.
544	/// - `beneficiary`: The new owner for the assets.
545	///
546	/// Safety: No concerns.
547	///
548	/// Kind: *Command*.
549	///
550	/// Errors:
551	TransferAsset { assets: MultiAssets, beneficiary: MultiLocation },
552
553	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
554	/// under the ownership of `dest` within this consensus system (i.e. its sovereign account).
555	///
556	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given
557	/// `xcm`.
558	///
559	/// - `assets`: The asset(s) to be withdrawn.
560	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
561	///   beneficiary for the assets and the notification target for the reserve asset deposit
562	///   message.
563	/// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which
564	///   is sent onwards to `dest`.
565	///
566	/// Safety: No concerns.
567	///
568	/// Kind: *Command*.
569	///
570	/// Errors:
571	TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> },
572
573	/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed
574	/// by the kind of origin `origin_type`.
575	///
576	/// - `origin_type`: The means of expressing the message origin as a dispatch origin.
577	/// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight
578	///   and will be used in the weight determination arithmetic.
579	/// - `call`: The encoded transaction to be applied.
580	///
581	/// Safety: No concerns.
582	///
583	/// Kind: *Command*.
584	///
585	/// Errors:
586	Transact {
587		origin_type: OriginKind,
588		#[codec(compact)]
589		require_weight_at_most: u64,
590		call: DoubleEncoded<RuntimeCall>,
591	},
592
593	/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by
594	/// the relay-chain to a para.
595	///
596	/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel
597	///   opening.
598	/// - `max_message_size`: The maximum size of a message proposed by the sender.
599	/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
600	///
601	/// Safety: The message should originate directly from the relay-chain.
602	///
603	/// Kind: *System Notification*
604	HrmpNewChannelOpenRequest {
605		#[codec(compact)]
606		sender: u32,
607		#[codec(compact)]
608		max_message_size: u32,
609		#[codec(compact)]
610		max_capacity: u32,
611	},
612
613	/// A message to notify about that a previously sent open channel request has been accepted by
614	/// the recipient. That means that the channel will be opened during the next relay-chain
615	/// session change. This message is meant to be sent by the relay-chain to a para.
616	///
617	/// Safety: The message should originate directly from the relay-chain.
618	///
619	/// Kind: *System Notification*
620	///
621	/// Errors:
622	HrmpChannelAccepted {
623		// NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp
624		// items; and b) because the field's meaning is not obvious/mentioned from the item name.
625		#[codec(compact)]
626		recipient: u32,
627	},
628
629	/// A message to notify that the other party in an open channel decided to close it. In
630	/// particular, `initiator` is going to close the channel opened from `sender` to the
631	/// `recipient`. The close will be enacted at the next relay-chain session change. This message
632	/// is meant to be sent by the relay-chain to a para.
633	///
634	/// Safety: The message should originate directly from the relay-chain.
635	///
636	/// Kind: *System Notification*
637	///
638	/// Errors:
639	HrmpChannelClosing {
640		#[codec(compact)]
641		initiator: u32,
642		#[codec(compact)]
643		sender: u32,
644		#[codec(compact)]
645		recipient: u32,
646	},
647
648	/// Clear the origin.
649	///
650	/// This may be used by the XCM author to ensure that later instructions cannot command the
651	/// authority of the origin (e.g. if they are being relayed from an untrusted source, as often
652	/// the case with `ReserveAssetDeposited`).
653	///
654	/// Safety: No concerns.
655	///
656	/// Kind: *Command*.
657	///
658	/// Errors:
659	ClearOrigin,
660
661	/// Mutate the origin to some interior location.
662	///
663	/// Kind: *Command*
664	///
665	/// Errors:
666	DescendOrigin(InteriorMultiLocation),
667
668	/// Immediately report the contents of the Error Register to the given destination via XCM.
669	///
670	/// A `QueryResponse` message of type `ExecutionOutcome` is sent to `dest` with the given
671	/// `query_id` and the outcome of the XCM.
672	///
673	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
674	/// - `dest`: A valid destination for the returned XCM message.
675	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
676	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
677	///   response may not execute at all.
678	///
679	/// Kind: *Command*
680	///
681	/// Errors:
682	ReportError {
683		#[codec(compact)]
684		query_id: QueryId,
685		dest: MultiLocation,
686		#[codec(compact)]
687		max_response_weight: u64,
688	},
689
690	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
691	/// the ownership of `beneficiary` within this consensus system.
692	///
693	/// - `assets`: The asset(s) to remove from holding.
694	/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding.
695	///   Only the first `max_assets` assets/instances of those matched by `assets` will be
696	///   removed, prioritized under standard asset ordering. Any others will remain in holding.
697	/// - `beneficiary`: The new owner for the assets.
698	///
699	/// Kind: *Command*
700	///
701	/// Errors:
702	DepositAsset {
703		assets: MultiAssetFilter,
704		#[codec(compact)]
705		max_assets: u32,
706		beneficiary: MultiLocation,
707	},
708
709	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
710	/// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign
711	/// account).
712	///
713	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
714	///
715	/// - `assets`: The asset(s) to remove from holding.
716	/// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding.
717	///   Only the first `max_assets` assets/instances of those matched by `assets` will be
718	///   removed, prioritized under standard asset ordering. Any others will remain in holding.
719	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
720	///   beneficiary for the assets and the notification target for the reserve asset deposit
721	///   message.
722	/// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is
723	///   sent onwards to `dest`.
724	///
725	/// Kind: *Command*
726	///
727	/// Errors:
728	DepositReserveAsset {
729		assets: MultiAssetFilter,
730		#[codec(compact)]
731		max_assets: u32,
732		dest: MultiLocation,
733		xcm: Xcm<()>,
734	},
735
736	/// Remove the asset(s) (`give`) from the Holding Register and replace them with alternative
737	/// assets.
738	///
739	/// The minimum amount of assets to be received into the Holding Register for the order not to
740	/// fail may be stated.
741	///
742	/// - `give`: The asset(s) to remove from holding.
743	/// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for.
744	///
745	/// Kind: *Command*
746	///
747	/// Errors:
748	ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets },
749
750	/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a
751	/// reserve location.
752	///
753	/// - `assets`: The asset(s) to remove from holding.
754	/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The
755	///   sovereign account of this consensus system *on the reserve location* will have
756	///   appropriate assets withdrawn and `effects` will be executed on them. There will typically
757	///   be only one valid location on any given asset/chain combination.
758	/// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve
759	///   location*.
760	///
761	/// Kind: *Command*
762	///
763	/// Errors:
764	InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> },
765
766	/// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message
767	/// to a `dest` location.
768	///
769	/// - `assets`: The asset(s) to remove from holding.
770	/// - `dest`: A valid location that respects teleports coming from this location.
771	/// - `xcm`: The instructions to execute on the assets once arrived *on the destination
772	///   location*.
773	///
774	/// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for
775	/// all `assets`. If it does not, then the assets may be lost.
776	///
777	/// Kind: *Command*
778	///
779	/// Errors:
780	InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },
781
782	/// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a
783	/// portion thereof.
784	///
785	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
786	/// - `dest`: A valid destination for the returned XCM message. This may be limited to the
787	///   current origin.
788	/// - `assets`: A filter for the assets that should be reported back. The assets reported back
789	///   will be, asset-wise, *the lesser of this value and the holding register*. No wildcards
790	///   will be used when reporting assets back.
791	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
792	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
793	///   response may not execute at all.
794	///
795	/// Kind: *Command*
796	///
797	/// Errors:
798	QueryHolding {
799		#[codec(compact)]
800		query_id: QueryId,
801		dest: MultiLocation,
802		assets: MultiAssetFilter,
803		#[codec(compact)]
804		max_response_weight: u64,
805	},
806
807	/// Pay for the execution of some XCM `xcm` and `orders` with up to `weight`
808	/// picoseconds of execution time, paying for this with up to `fees` from the Holding Register.
809	///
810	/// - `fees`: The asset(s) to remove from the Holding Register to pay for fees.
811	/// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the
812	///   expected maximum weight of the total XCM to be executed for the
813	///   `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed.
814	///
815	/// Kind: *Command*
816	///
817	/// Errors:
818	BuyExecution { fees: MultiAsset, weight_limit: WeightLimit },
819
820	/// Refund any surplus weight previously bought with `BuyExecution`.
821	///
822	/// Kind: *Command*
823	///
824	/// Errors: None.
825	RefundSurplus,
826
827	/// Set the Error Handler Register. This is code that should be called in the case of an error
828	/// happening.
829	///
830	/// An error occurring within execution of this code will _NOT_ result in the error register
831	/// being set, nor will an error handler be called due to it. The error handler and appendix
832	/// may each still be set.
833	///
834	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
835	/// weight however includes only the difference between the previous handler and the new
836	/// handler, which can reasonably be negative, which would result in a surplus.
837	///
838	/// Kind: *Command*
839	///
840	/// Errors: None.
841	SetErrorHandler(Xcm<RuntimeCall>),
842
843	/// Set the Appendix Register. This is code that should be called after code execution
844	/// (including the error handler if any) is finished. This will be called regardless of whether
845	/// an error occurred.
846	///
847	/// Any error occurring due to execution of this code will result in the error register being
848	/// set, and the error handler (if set) firing.
849	///
850	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
851	/// weight however includes only the difference between the previous appendix and the new
852	/// appendix, which can reasonably be negative, which would result in a surplus.
853	///
854	/// Kind: *Command*
855	///
856	/// Errors: None.
857	SetAppendix(Xcm<RuntimeCall>),
858
859	/// Clear the Error Register.
860	///
861	/// Kind: *Command*
862	///
863	/// Errors: None.
864	ClearError,
865
866	/// Create some assets which are being held on behalf of the origin.
867	///
868	/// - `assets`: The assets which are to be claimed. This must match exactly with the assets
869	///   claimable by the origin of the ticket.
870	/// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the
871	///   asset.
872	///
873	/// Kind: *Command*
874	///
875	/// Errors:
876	ClaimAsset { assets: MultiAssets, ticket: MultiLocation },
877
878	/// Always throws an error of type `Trap`.
879	///
880	/// Kind: *Command*
881	///
882	/// Errors:
883	/// - `Trap`: All circumstances, whose inner value is the same as this item's inner value.
884	Trap(#[codec(compact)] u64),
885
886	/// Ask the destination system to respond with the most recent version of XCM that they
887	/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
888	/// responses when they happen.
889	///
890	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
891	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
892	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
893	///   response may not execute at all.
894	///
895	/// Kind: *Command*
896	///
897	/// Errors: *Fallible*
898	SubscribeVersion {
899		#[codec(compact)]
900		query_id: QueryId,
901		#[codec(compact)]
902		max_response_weight: u64,
903	},
904
905	/// Cancel the effect of a previous `SubscribeVersion` instruction.
906	///
907	/// Kind: *Command*
908	///
909	/// Errors: *Fallible*
910	UnsubscribeVersion,
911}
912
913impl<RuntimeCall> Xcm<RuntimeCall> {
914	pub fn into<C>(self) -> Xcm<C> {
915		Xcm::from(self)
916	}
917	pub fn from<C>(xcm: Xcm<C>) -> Self {
918		Self(xcm.0.into_iter().map(Instruction::<RuntimeCall>::from).collect())
919	}
920}
921
922impl<RuntimeCall> Instruction<RuntimeCall> {
923	pub fn into<C>(self) -> Instruction<C> {
924		Instruction::from(self)
925	}
926	pub fn from<C>(xcm: Instruction<C>) -> Self {
927		use Instruction::*;
928		match xcm {
929			WithdrawAsset(assets) => WithdrawAsset(assets),
930			ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
931			ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
932			QueryResponse { query_id, response, max_weight } =>
933				QueryResponse { query_id, response, max_weight },
934			TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
935			TransferReserveAsset { assets, dest, xcm } =>
936				TransferReserveAsset { assets, dest, xcm },
937			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
938				HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
939			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
940			HrmpChannelClosing { initiator, sender, recipient } =>
941				HrmpChannelClosing { initiator, sender, recipient },
942			Transact { origin_type, require_weight_at_most, call } =>
943				Transact { origin_type, require_weight_at_most, call: call.into() },
944			ReportError { query_id, dest, max_response_weight } =>
945				ReportError { query_id, dest, max_response_weight },
946			DepositAsset { assets, max_assets, beneficiary } =>
947				DepositAsset { assets, max_assets, beneficiary },
948			DepositReserveAsset { assets, max_assets, dest, xcm } =>
949				DepositReserveAsset { assets, max_assets, dest, xcm },
950			ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
951			InitiateReserveWithdraw { assets, reserve, xcm } =>
952				InitiateReserveWithdraw { assets, reserve, xcm },
953			InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
954			QueryHolding { query_id, dest, assets, max_response_weight } =>
955				QueryHolding { query_id, dest, assets, max_response_weight },
956			BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
957			ClearOrigin => ClearOrigin,
958			DescendOrigin(who) => DescendOrigin(who),
959			RefundSurplus => RefundSurplus,
960			SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
961			SetAppendix(xcm) => SetAppendix(xcm.into()),
962			ClearError => ClearError,
963			ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
964			Trap(code) => Trap(code),
965			SubscribeVersion { query_id, max_response_weight } =>
966				SubscribeVersion { query_id, max_response_weight },
967			UnsubscribeVersion => UnsubscribeVersion,
968		}
969	}
970}
971
972// TODO: Automate Generation
973impl<RuntimeCall, W: XcmWeightInfo<RuntimeCall>> GetWeight<W> for Instruction<RuntimeCall> {
974	fn weight(&self) -> sp_weights::Weight {
975		use Instruction::*;
976		match self {
977			WithdrawAsset(assets) => sp_weights::Weight::from_parts(W::withdraw_asset(assets), 0),
978			ReserveAssetDeposited(assets) =>
979				sp_weights::Weight::from_parts(W::reserve_asset_deposited(assets), 0),
980			ReceiveTeleportedAsset(assets) =>
981				sp_weights::Weight::from_parts(W::receive_teleported_asset(assets), 0),
982			QueryResponse { query_id, response, max_weight } =>
983				sp_weights::Weight::from_parts(W::query_response(query_id, response, max_weight), 0),
984			TransferAsset { assets, beneficiary } =>
985				sp_weights::Weight::from_parts(W::transfer_asset(assets, beneficiary), 0),
986			TransferReserveAsset { assets, dest, xcm } =>
987				sp_weights::Weight::from_parts(W::transfer_reserve_asset(&assets, dest, xcm), 0),
988			Transact { origin_type, require_weight_at_most, call } =>
989				sp_weights::Weight::from_parts(
990					W::transact(origin_type, require_weight_at_most, call),
991					0,
992				),
993			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
994				sp_weights::Weight::from_parts(
995					W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
996					0,
997				),
998			HrmpChannelAccepted { recipient } =>
999				sp_weights::Weight::from_parts(W::hrmp_channel_accepted(recipient), 0),
1000			HrmpChannelClosing { initiator, sender, recipient } => sp_weights::Weight::from_parts(
1001				W::hrmp_channel_closing(initiator, sender, recipient),
1002				0,
1003			),
1004			ClearOrigin => sp_weights::Weight::from_parts(W::clear_origin(), 0),
1005			DescendOrigin(who) => sp_weights::Weight::from_parts(W::descend_origin(who), 0),
1006			ReportError { query_id, dest, max_response_weight } => sp_weights::Weight::from_parts(
1007				W::report_error(query_id, dest, max_response_weight),
1008				0,
1009			),
1010			DepositAsset { assets, max_assets, beneficiary } =>
1011				sp_weights::Weight::from_parts(W::deposit_asset(assets, max_assets, beneficiary), 0),
1012			DepositReserveAsset { assets, max_assets, dest, xcm } =>
1013				sp_weights::Weight::from_parts(
1014					W::deposit_reserve_asset(assets, max_assets, dest, xcm),
1015					0,
1016				),
1017			ExchangeAsset { give, receive } =>
1018				sp_weights::Weight::from_parts(W::exchange_asset(give, receive), 0),
1019			InitiateReserveWithdraw { assets, reserve, xcm } => sp_weights::Weight::from_parts(
1020				W::initiate_reserve_withdraw(assets, reserve, xcm),
1021				0,
1022			),
1023			InitiateTeleport { assets, dest, xcm } =>
1024				sp_weights::Weight::from_parts(W::initiate_teleport(assets, dest, xcm), 0),
1025			QueryHolding { query_id, dest, assets, max_response_weight } =>
1026				sp_weights::Weight::from_parts(
1027					W::query_holding(query_id, dest, assets, max_response_weight),
1028					0,
1029				),
1030			BuyExecution { fees, weight_limit } =>
1031				sp_weights::Weight::from_parts(W::buy_execution(fees, weight_limit), 0),
1032			RefundSurplus => sp_weights::Weight::from_parts(W::refund_surplus(), 0),
1033			SetErrorHandler(xcm) => sp_weights::Weight::from_parts(W::set_error_handler(xcm), 0),
1034			SetAppendix(xcm) => sp_weights::Weight::from_parts(W::set_appendix(xcm), 0),
1035			ClearError => sp_weights::Weight::from_parts(W::clear_error(), 0),
1036			ClaimAsset { assets, ticket } =>
1037				sp_weights::Weight::from_parts(W::claim_asset(assets, ticket), 0),
1038			Trap(code) => sp_weights::Weight::from_parts(W::trap(code), 0),
1039			SubscribeVersion { query_id, max_response_weight } => sp_weights::Weight::from_parts(
1040				W::subscribe_version(query_id, max_response_weight),
1041				0,
1042			),
1043			UnsubscribeVersion => sp_weights::Weight::from_parts(W::unsubscribe_version(), 0),
1044		}
1045	}
1046}
1047
1048pub mod opaque {
1049	/// The basic concrete type of `Xcm`, which doesn't make any assumptions about the
1050	/// format of a call other than it is pre-encoded.
1051	pub type Xcm = super::Xcm<()>;
1052
1053	/// The basic concrete type of `Instruction`, which doesn't make any assumptions about the
1054	/// format of a call other than it is pre-encoded.
1055	pub type Instruction = super::Instruction<()>;
1056}
1057
1058// Convert from a v3 response to a v2 response
1059impl TryFrom<NewResponse> for Response {
1060	type Error = ();
1061	fn try_from(response: NewResponse) -> result::Result<Self, ()> {
1062		Ok(match response {
1063			NewResponse::Assets(assets) => Self::Assets(assets.try_into()?),
1064			NewResponse::Version(version) => Self::Version(version),
1065			NewResponse::ExecutionResult(error) => Self::ExecutionResult(match error {
1066				Some((i, e)) => Some((i, e.try_into()?)),
1067				None => None,
1068			}),
1069			NewResponse::Null => Self::Null,
1070			_ => return Err(()),
1071		})
1072	}
1073}
1074
1075// Convert from a v3 XCM to a v2 XCM.
1076impl<RuntimeCall> TryFrom<NewXcm<RuntimeCall>> for Xcm<RuntimeCall> {
1077	type Error = ();
1078	fn try_from(new_xcm: NewXcm<RuntimeCall>) -> result::Result<Self, ()> {
1079		Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1080	}
1081}
1082
1083// Convert from a v3 instruction to a v2 instruction
1084impl<RuntimeCall> TryFrom<NewInstruction<RuntimeCall>> for Instruction<RuntimeCall> {
1085	type Error = ();
1086	fn try_from(instruction: NewInstruction<RuntimeCall>) -> result::Result<Self, ()> {
1087		use NewInstruction::*;
1088		Ok(match instruction {
1089			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1090			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1091			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1092			QueryResponse { query_id, response, max_weight, .. } => Self::QueryResponse {
1093				query_id,
1094				response: response.try_into()?,
1095				max_weight: max_weight.ref_time(),
1096			},
1097			TransferAsset { assets, beneficiary } => Self::TransferAsset {
1098				assets: assets.try_into()?,
1099				beneficiary: beneficiary.try_into()?,
1100			},
1101			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1102				assets: assets.try_into()?,
1103				dest: dest.try_into()?,
1104				xcm: xcm.try_into()?,
1105			},
1106			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1107				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1108			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1109			HrmpChannelClosing { initiator, sender, recipient } =>
1110				Self::HrmpChannelClosing { initiator, sender, recipient },
1111			Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
1112				origin_type: origin_kind.into(),
1113				require_weight_at_most: require_weight_at_most.ref_time(),
1114				call: call.into(),
1115			},
1116			ReportError(response_info) => Self::ReportError {
1117				query_id: response_info.query_id,
1118				dest: response_info.destination.try_into()?,
1119				max_response_weight: response_info.max_weight.ref_time(),
1120			},
1121			DepositAsset { assets, beneficiary } => {
1122				let max_assets = assets.count().ok_or(())?;
1123				let beneficiary = beneficiary.try_into()?;
1124				let assets = assets.try_into()?;
1125				Self::DepositAsset { assets, max_assets, beneficiary }
1126			},
1127			DepositReserveAsset { assets, dest, xcm } => {
1128				let max_assets = assets.count().ok_or(())?;
1129				let dest = dest.try_into()?;
1130				let xcm = xcm.try_into()?;
1131				let assets = assets.try_into()?;
1132				Self::DepositReserveAsset { assets, max_assets, dest, xcm }
1133			},
1134			ExchangeAsset { give, want, .. } => {
1135				let give = give.try_into()?;
1136				let receive = want.try_into()?;
1137				Self::ExchangeAsset { give, receive }
1138			},
1139			InitiateReserveWithdraw { assets, reserve, xcm } => {
1140				// No `max_assets` here, so if there's a connt, then we cannot translate.
1141				let assets = assets.try_into()?;
1142				let reserve = reserve.try_into()?;
1143				let xcm = xcm.try_into()?;
1144				Self::InitiateReserveWithdraw { assets, reserve, xcm }
1145			},
1146			InitiateTeleport { assets, dest, xcm } => {
1147				// No `max_assets` here, so if there's a connt, then we cannot translate.
1148				let assets = assets.try_into()?;
1149				let dest = dest.try_into()?;
1150				let xcm = xcm.try_into()?;
1151				Self::InitiateTeleport { assets, dest, xcm }
1152			},
1153			ReportHolding { response_info, assets } => Self::QueryHolding {
1154				query_id: response_info.query_id,
1155				dest: response_info.destination.try_into()?,
1156				assets: assets.try_into()?,
1157				max_response_weight: response_info.max_weight.ref_time(),
1158			},
1159			BuyExecution { fees, weight_limit } => {
1160				let fees = fees.try_into()?;
1161				let weight_limit = weight_limit.try_into()?;
1162				Self::BuyExecution { fees, weight_limit }
1163			},
1164			ClearOrigin => Self::ClearOrigin,
1165			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1166			RefundSurplus => Self::RefundSurplus,
1167			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1168			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1169			ClearError => Self::ClearError,
1170			ClaimAsset { assets, ticket } => {
1171				let assets = assets.try_into()?;
1172				let ticket = ticket.try_into()?;
1173				Self::ClaimAsset { assets, ticket }
1174			},
1175			Trap(code) => Self::Trap(code),
1176			SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion {
1177				query_id,
1178				max_response_weight: max_response_weight.ref_time(),
1179			},
1180			UnsubscribeVersion => Self::UnsubscribeVersion,
1181			i => {
1182				log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2");
1183				return Err(());
1184			},
1185		})
1186	}
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191	use super::{prelude::*, *};
1192
1193	#[test]
1194	fn decoding_respects_limit() {
1195		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1196		let encoded = max_xcm.encode();
1197		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1198
1199		let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1200		let encoded = big_xcm.encode();
1201		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1202
1203		let nested_xcm = Xcm::<()>(vec![
1204			DepositReserveAsset {
1205				assets: All.into(),
1206				dest: Here.into(),
1207				xcm: max_xcm,
1208				max_assets: 1,
1209			};
1210			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1211		]);
1212		let encoded = nested_xcm.encode();
1213		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1214
1215		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1216		let encoded = even_more_nested_xcm.encode();
1217		assert_eq!(encoded.len(), 345730);
1218		// This should not decode since the limit is 100
1219		assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1220		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1221	}
1222}