referrerpolicy=no-referrer-when-downgrade

staging_xcm/v4/
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//! Version 4 of the Cross-Consensus Message format data structures.
18
19pub use super::v3::GetWeight;
20use super::{
21	v3::{
22		Instruction as OldInstruction, PalletInfo as OldPalletInfo,
23		QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
24	},
25	v5::{
26		Instruction as NewInstruction, PalletInfo as NewPalletInfo,
27		QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm,
28	},
29};
30use crate::{utils::decode_xcm_instructions, DoubleEncoded};
31use alloc::{vec, vec::Vec};
32use bounded_collections::{parameter_types, BoundedVec};
33use codec::{
34	self, Decode, DecodeWithMemTracking, Encode, Error as CodecError, Input as CodecInput,
35	MaxEncodedLen,
36};
37use core::{fmt::Debug, result};
38use derive_where::derive_where;
39use frame_support::dispatch::GetDispatchInfo;
40use scale_info::TypeInfo;
41
42mod asset;
43mod junction;
44pub(crate) mod junctions;
45mod location;
46mod traits;
47
48pub use asset::{
49	Asset, AssetFilter, AssetId, AssetInstance, Assets, Fungibility, WildAsset, WildFungibility,
50	MAX_ITEMS_IN_ASSETS,
51};
52pub use junction::{BodyId, BodyPart, Junction, NetworkId};
53pub use junctions::Junctions;
54pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen};
55pub use traits::{
56	send_xcm, validate_send, Error, ExecuteXcm, Outcome, PreparedMessage, Reanchorable, Result,
57	SendError, SendResult, SendXcm, Weight, XcmHash,
58};
59// These parts of XCM v3 are unchanged in XCM v4, and are re-imported here.
60pub use super::v3::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit};
61
62/// This module's XCM version.
63pub const VERSION: super::Version = 4;
64
65/// An identifier for a query.
66pub type QueryId = u64;
67
68#[derive(Default, Encode, DecodeWithMemTracking, TypeInfo)]
69#[derive_where(Clone, Eq, PartialEq, Debug)]
70#[codec(encode_bound())]
71#[codec(decode_bound())]
72#[scale_info(bounds(), skip_type_params(Call))]
73pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
74
75impl<Call> Decode for Xcm<Call> {
76	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
77		Ok(Xcm(decode_xcm_instructions(input)?))
78	}
79}
80
81impl<Call> Xcm<Call> {
82	/// Create an empty instance.
83	pub fn new() -> Self {
84		Self(vec![])
85	}
86
87	/// Return `true` if no instructions are held in `self`.
88	pub fn is_empty(&self) -> bool {
89		self.0.is_empty()
90	}
91
92	/// Return the number of instructions held in `self`.
93	pub fn len(&self) -> usize {
94		self.0.len()
95	}
96
97	/// Return a reference to the inner value.
98	pub fn inner(&self) -> &[Instruction<Call>] {
99		&self.0
100	}
101
102	/// Return a mutable reference to the inner value.
103	pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
104		&mut self.0
105	}
106
107	/// Consume and return the inner value.
108	pub fn into_inner(self) -> Vec<Instruction<Call>> {
109		self.0
110	}
111
112	/// Return an iterator over references to the items.
113	pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
114		self.0.iter()
115	}
116
117	/// Return an iterator over mutable references to the items.
118	pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
119		self.0.iter_mut()
120	}
121
122	/// Consume and return an iterator over the items.
123	pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
124		self.0.into_iter()
125	}
126
127	/// Consume and either return `self` if it contains some instructions, or if it's empty, then
128	/// instead return the result of `f`.
129	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
130		if self.0.is_empty() {
131			f()
132		} else {
133			self
134		}
135	}
136
137	/// Return the first instruction, if any.
138	pub fn first(&self) -> Option<&Instruction<Call>> {
139		self.0.first()
140	}
141
142	/// Return the last instruction, if any.
143	pub fn last(&self) -> Option<&Instruction<Call>> {
144		self.0.last()
145	}
146
147	/// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise).
148	pub fn only(&self) -> Option<&Instruction<Call>> {
149		if self.0.len() == 1 {
150			self.0.first()
151		} else {
152			None
153		}
154	}
155
156	/// Return the only instruction, contained in `Self`, iff only one exists (returns `self`
157	/// otherwise).
158	pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
159		if self.0.len() == 1 {
160			self.0.pop().ok_or(self)
161		} else {
162			Err(self)
163		}
164	}
165}
166
167impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
168	fn from(c: Vec<Instruction<Call>>) -> Self {
169		Self(c)
170	}
171}
172
173impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
174	fn from(c: Xcm<Call>) -> Self {
175		c.0
176	}
177}
178
179/// A prelude for importing all types typically used when interacting with XCM messages.
180pub mod prelude {
181	mod contents {
182		pub use super::super::{
183			send_xcm, validate_send, Ancestor, AncestorThen, Asset,
184			AssetFilter::{self, *},
185			AssetId,
186			AssetInstance::{self, *},
187			Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
188			Fungibility::{self, *},
189			Instruction::*,
190			InteriorLocation,
191			Junction::{self, *},
192			Junctions::{self, Here},
193			Location, MaybeErrorCode,
194			NetworkId::{self, *},
195			OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
196			QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult,
197			SendXcm, Weight,
198			WeightLimit::{self, *},
199			WildAsset::{self, *},
200			WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
201			XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
202		};
203	}
204	pub use super::{Instruction, Xcm};
205	pub use contents::*;
206	pub mod opaque {
207		pub use super::{
208			super::opaque::{Instruction, Xcm},
209			contents::*,
210		};
211	}
212}
213
214parameter_types! {
215	pub MaxPalletNameLen: u32 = 48;
216	pub MaxPalletsInfo: u32 = 64;
217}
218
219#[derive(
220	Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
221)]
222pub struct PalletInfo {
223	#[codec(compact)]
224	pub index: u32,
225	pub name: BoundedVec<u8, MaxPalletNameLen>,
226	pub module_name: BoundedVec<u8, MaxPalletNameLen>,
227	#[codec(compact)]
228	pub major: u32,
229	#[codec(compact)]
230	pub minor: u32,
231	#[codec(compact)]
232	pub patch: u32,
233}
234
235impl TryInto<OldPalletInfo> for PalletInfo {
236	type Error = ();
237
238	fn try_into(self) -> result::Result<OldPalletInfo, Self::Error> {
239		OldPalletInfo::new(
240			self.index,
241			self.name.into_inner(),
242			self.module_name.into_inner(),
243			self.major,
244			self.minor,
245			self.patch,
246		)
247		.map_err(|_| ())
248	}
249}
250
251impl TryInto<NewPalletInfo> for PalletInfo {
252	type Error = ();
253
254	fn try_into(self) -> result::Result<NewPalletInfo, Self::Error> {
255		NewPalletInfo::new(
256			self.index,
257			self.name.into_inner(),
258			self.module_name.into_inner(),
259			self.major,
260			self.minor,
261			self.patch,
262		)
263		.map_err(|_| ())
264	}
265}
266
267impl PalletInfo {
268	pub fn new(
269		index: u32,
270		name: Vec<u8>,
271		module_name: Vec<u8>,
272		major: u32,
273		minor: u32,
274		patch: u32,
275	) -> result::Result<Self, Error> {
276		let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
277		let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
278
279		Ok(Self { index, name, module_name, major, minor, patch })
280	}
281}
282
283/// Response data to a query.
284#[derive(
285	Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
286)]
287pub enum Response {
288	/// No response. Serves as a neutral default.
289	Null,
290	/// Some assets.
291	Assets(Assets),
292	/// The outcome of an XCM instruction.
293	ExecutionResult(Option<(u32, Error)>),
294	/// An XCM version.
295	Version(super::Version),
296	/// The index, instance name, pallet name and version of some pallets.
297	PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
298	/// The status of a dispatch attempt using `Transact`.
299	DispatchResult(MaybeErrorCode),
300}
301
302impl Default for Response {
303	fn default() -> Self {
304		Self::Null
305	}
306}
307
308impl TryFrom<OldResponse> for Response {
309	type Error = ();
310
311	fn try_from(old: OldResponse) -> result::Result<Self, Self::Error> {
312		use OldResponse::*;
313		Ok(match old {
314			Null => Self::Null,
315			Assets(assets) => Self::Assets(assets.try_into()?),
316			ExecutionResult(result) => {
317				Self::ExecutionResult(result.map(|(num, old_error)| (num, old_error.into())))
318			},
319			Version(version) => Self::Version(version),
320			PalletsInfo(pallet_info) => {
321				let inner = pallet_info
322					.into_iter()
323					.map(TryInto::try_into)
324					.collect::<result::Result<Vec<_>, _>>()?;
325				Self::PalletsInfo(
326					BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
327				)
328			},
329			DispatchResult(maybe_error) => Self::DispatchResult(maybe_error),
330		})
331	}
332}
333
334impl TryFrom<NewResponse> for Response {
335	type Error = ();
336
337	fn try_from(new: NewResponse) -> result::Result<Self, Self::Error> {
338		use NewResponse::*;
339		Ok(match new {
340			Null => Self::Null,
341			Assets(assets) => Self::Assets(assets.try_into()?),
342			ExecutionResult(result) => Self::ExecutionResult(
343				result
344					.map(|(num, new_error)| (num, new_error.try_into()))
345					.map(|(num, result)| result.map(|inner| (num, inner)))
346					.transpose()?,
347			),
348			Version(version) => Self::Version(version),
349			PalletsInfo(pallet_info) => {
350				let inner = pallet_info
351					.into_iter()
352					.map(TryInto::try_into)
353					.collect::<result::Result<Vec<_>, _>>()?;
354				Self::PalletsInfo(
355					BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
356				)
357			},
358			DispatchResult(maybe_error) => {
359				Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?)
360			},
361		})
362	}
363}
364
365/// Information regarding the composition of a query response.
366#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
367pub struct QueryResponseInfo {
368	/// The destination to which the query response message should be send.
369	pub destination: Location,
370	/// The `query_id` field of the `QueryResponse` message.
371	#[codec(compact)]
372	pub query_id: QueryId,
373	/// The `max_weight` field of the `QueryResponse` message.
374	pub max_weight: Weight,
375}
376
377impl TryFrom<NewQueryResponseInfo> for QueryResponseInfo {
378	type Error = ();
379
380	fn try_from(new: NewQueryResponseInfo) -> result::Result<Self, Self::Error> {
381		Ok(Self {
382			destination: new.destination.try_into()?,
383			query_id: new.query_id,
384			max_weight: new.max_weight,
385		})
386	}
387}
388
389impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
390	type Error = ();
391
392	fn try_from(old: OldQueryResponseInfo) -> result::Result<Self, Self::Error> {
393		Ok(Self {
394			destination: old.destination.try_into()?,
395			query_id: old.query_id,
396			max_weight: old.max_weight,
397		})
398	}
399}
400
401/// Contextual data pertaining to a specific list of XCM instructions.
402#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
403pub struct XcmContext {
404	/// The current value of the Origin register of the `XCVM`.
405	pub origin: Option<Location>,
406	/// The identity of the XCM; this may be a hash of its versioned encoding but could also be
407	/// a high-level identity set by an appropriate barrier.
408	pub message_id: XcmHash,
409	/// The current value of the Topic register of the `XCVM`.
410	pub topic: Option<[u8; 32]>,
411}
412
413impl XcmContext {
414	/// Constructor which sets the message ID to the supplied parameter and leaves the origin and
415	/// topic unset.
416	pub fn with_message_id(message_id: XcmHash) -> XcmContext {
417		XcmContext { origin: None, message_id, topic: None }
418	}
419}
420
421/// Cross-Consensus Message: A message from one consensus system to another.
422///
423/// Consensus systems that may send and receive messages include blockchains and smart contracts.
424///
425/// All messages are delivered from a known *origin*, expressed as a `Location`.
426///
427/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the
428/// outer XCM format, known as `VersionedXcm`.
429#[derive(
430	Encode,
431	Decode,
432	DecodeWithMemTracking,
433	TypeInfo,
434	xcm_procedural::XcmWeightInfoTrait,
435	xcm_procedural::Builder,
436)]
437#[derive_where(Clone, Eq, PartialEq, Debug)]
438#[codec(encode_bound())]
439#[codec(decode_bound())]
440#[codec(decode_with_mem_tracking_bound())]
441#[scale_info(bounds(), skip_type_params(Call))]
442pub enum Instruction<Call> {
443	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding
444	/// Register.
445	///
446	/// - `assets`: The asset(s) to be withdrawn into holding.
447	///
448	/// Kind: *Command*.
449	///
450	/// Errors:
451	#[builder(loads_holding)]
452	WithdrawAsset(Assets),
453
454	/// Asset(s) (`assets`) have been received into the ownership of this system on the `origin`
455	/// system and equivalent derivatives should be placed into the Holding Register.
456	///
457	/// - `assets`: The asset(s) that are minted into holding.
458	///
459	/// Safety: `origin` must be trusted to have received and be storing `assets` such that they
460	/// may later be withdrawn should this system send a corresponding message.
461	///
462	/// Kind: *Trusted Indication*.
463	///
464	/// Errors:
465	#[builder(loads_holding)]
466	ReserveAssetDeposited(Assets),
467
468	/// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should
469	/// be created and placed into the Holding Register.
470	///
471	/// - `assets`: The asset(s) that are minted into the Holding Register.
472	///
473	/// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets`
474	/// prior as a consequence of sending this message.
475	///
476	/// Kind: *Trusted Indication*.
477	///
478	/// Errors:
479	#[builder(loads_holding)]
480	ReceiveTeleportedAsset(Assets),
481
482	/// Respond with information that the local system is expecting.
483	///
484	/// - `query_id`: The identifier of the query that resulted in this message being sent.
485	/// - `response`: The message content.
486	/// - `max_weight`: The maximum weight that handling this response should take.
487	/// - `querier`: The location responsible for the initiation of the response, if there is one.
488	///   In general this will tend to be the same location as the receiver of this message. NOTE:
489	///   As usual, this is interpreted from the perspective of the receiving consensus system.
490	///
491	/// Safety: Since this is information only, there are no immediate concerns. However, it should
492	/// be remembered that even if the Origin behaves reasonably, it can always be asked to make
493	/// a response to a third-party chain who may or may not be expecting the response. Therefore
494	/// the `querier` should be checked to match the expected value.
495	///
496	/// Kind: *Information*.
497	///
498	/// Errors:
499	QueryResponse {
500		#[codec(compact)]
501		query_id: QueryId,
502		response: Response,
503		max_weight: Weight,
504		querier: Option<Location>,
505	},
506
507	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
508	/// under the ownership of `beneficiary`.
509	///
510	/// - `assets`: The asset(s) to be withdrawn.
511	/// - `beneficiary`: The new owner for the assets.
512	///
513	/// Safety: No concerns.
514	///
515	/// Kind: *Command*.
516	///
517	/// Errors:
518	TransferAsset { assets: Assets, beneficiary: Location },
519
520	/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
521	/// under the ownership of `dest` within this consensus system (i.e. its sovereign account).
522	///
523	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given
524	/// `xcm`.
525	///
526	/// - `assets`: The asset(s) to be withdrawn.
527	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
528	///   beneficiary for the assets and the notification target for the reserve asset deposit
529	///   message.
530	/// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which
531	///   is sent onwards to `dest`.
532	///
533	/// Safety: No concerns.
534	///
535	/// Kind: *Command*.
536	///
537	/// Errors:
538	TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> },
539
540	/// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed
541	/// by the kind of origin `origin_kind`.
542	///
543	/// The Transact Status Register is set according to the result of dispatching the call.
544	///
545	/// - `origin_kind`: The means of expressing the message origin as a dispatch origin.
546	/// - `require_weight_at_most`: The weight of `call`; this should be at least the chain's
547	///   calculated weight and will be used in the weight determination arithmetic.
548	/// - `call`: The encoded transaction to be applied.
549	///
550	/// Safety: No concerns.
551	///
552	/// Kind: *Command*.
553	///
554	/// Errors:
555	Transact { origin_kind: OriginKind, require_weight_at_most: Weight, call: DoubleEncoded<Call> },
556
557	/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by
558	/// the relay-chain to a para.
559	///
560	/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel
561	///   opening.
562	/// - `max_message_size`: The maximum size of a message proposed by the sender.
563	/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
564	///
565	/// Safety: The message should originate directly from the relay-chain.
566	///
567	/// Kind: *System Notification*
568	HrmpNewChannelOpenRequest {
569		#[codec(compact)]
570		sender: u32,
571		#[codec(compact)]
572		max_message_size: u32,
573		#[codec(compact)]
574		max_capacity: u32,
575	},
576
577	/// A message to notify about that a previously sent open channel request has been accepted by
578	/// the recipient. That means that the channel will be opened during the next relay-chain
579	/// session change. This message is meant to be sent by the relay-chain to a para.
580	///
581	/// Safety: The message should originate directly from the relay-chain.
582	///
583	/// Kind: *System Notification*
584	///
585	/// Errors:
586	HrmpChannelAccepted {
587		// NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp
588		// items; and b) because the field's meaning is not obvious/mentioned from the item name.
589		#[codec(compact)]
590		recipient: u32,
591	},
592
593	/// A message to notify that the other party in an open channel decided to close it. In
594	/// particular, `initiator` is going to close the channel opened from `sender` to the
595	/// `recipient`. The close will be enacted at the next relay-chain session change. This message
596	/// is meant to be sent by the relay-chain to a para.
597	///
598	/// Safety: The message should originate directly from the relay-chain.
599	///
600	/// Kind: *System Notification*
601	///
602	/// Errors:
603	HrmpChannelClosing {
604		#[codec(compact)]
605		initiator: u32,
606		#[codec(compact)]
607		sender: u32,
608		#[codec(compact)]
609		recipient: u32,
610	},
611
612	/// Clear the origin.
613	///
614	/// This may be used by the XCM author to ensure that later instructions cannot command the
615	/// authority of the origin (e.g. if they are being relayed from an untrusted source, as often
616	/// the case with `ReserveAssetDeposited`).
617	///
618	/// Safety: No concerns.
619	///
620	/// Kind: *Command*.
621	///
622	/// Errors:
623	ClearOrigin,
624
625	/// Mutate the origin to some interior location.
626	///
627	/// Kind: *Command*
628	///
629	/// Errors:
630	DescendOrigin(InteriorLocation),
631
632	/// Immediately report the contents of the Error Register to the given destination via XCM.
633	///
634	/// A `QueryResponse` message of type `ExecutionOutcome` is sent to the described destination.
635	///
636	/// - `response_info`: Information for making the response.
637	///
638	/// Kind: *Command*
639	///
640	/// Errors:
641	ReportError(QueryResponseInfo),
642
643	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
644	/// the ownership of `beneficiary` within this consensus system.
645	///
646	/// - `assets`: The asset(s) to remove from holding.
647	/// - `beneficiary`: The new owner for the assets.
648	///
649	/// Kind: *Command*
650	///
651	/// Errors:
652	DepositAsset { assets: AssetFilter, beneficiary: Location },
653
654	/// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under
655	/// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign
656	/// account).
657	///
658	/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
659	///
660	/// - `assets`: The asset(s) to remove from holding.
661	/// - `dest`: The location whose sovereign account will own the assets and thus the effective
662	///   beneficiary for the assets and the notification target for the reserve asset deposit
663	///   message.
664	/// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is
665	///   sent onwards to `dest`.
666	///
667	/// Kind: *Command*
668	///
669	/// Errors:
670	DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
671
672	/// Remove the asset(s) (`want`) from the Holding Register and replace them with alternative
673	/// assets.
674	///
675	/// The minimum amount of assets to be received into the Holding Register for the order not to
676	/// fail may be stated.
677	///
678	/// - `give`: The maximum amount of assets to remove from holding.
679	/// - `want`: The minimum amount of assets which `give` should be exchanged for.
680	/// - `maximal`: If `true`, then prefer to give as much as possible up to the limit of `give`
681	///   and receive accordingly more. If `false`, then prefer to give as little as possible in
682	///   order to receive as little as possible while receiving at least `want`.
683	///
684	/// Kind: *Command*
685	///
686	/// Errors:
687	ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool },
688
689	/// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a
690	/// reserve location.
691	///
692	/// - `assets`: The asset(s) to remove from holding.
693	/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The
694	///   sovereign account of this consensus system *on the reserve location* will have
695	///   appropriate assets withdrawn and `effects` will be executed on them. There will typically
696	///   be only one valid location on any given asset/chain combination.
697	/// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve
698	///   location*.
699	///
700	/// Kind: *Command*
701	///
702	/// Errors:
703	InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> },
704
705	/// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message
706	/// to a `dest` location.
707	///
708	/// - `assets`: The asset(s) to remove from holding.
709	/// - `dest`: A valid location that respects teleports coming from this location.
710	/// - `xcm`: The instructions to execute on the assets once arrived *on the destination
711	///   location*.
712	///
713	/// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for
714	/// all `assets`. If it does not, then the assets may be lost.
715	///
716	/// Kind: *Command*
717	///
718	/// Errors:
719	InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
720
721	/// Report to a given destination the contents of the Holding Register.
722	///
723	/// A `QueryResponse` message of type `Assets` is sent to the described destination.
724	///
725	/// - `response_info`: Information for making the response.
726	/// - `assets`: A filter for the assets that should be reported back. The assets reported back
727	///   will be, asset-wise, *the lesser of this value and the holding register*. No wildcards
728	///   will be used when reporting assets back.
729	///
730	/// Kind: *Command*
731	///
732	/// Errors:
733	ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter },
734
735	/// Pay for the execution of some XCM `xcm` and `orders` with up to `weight`
736	/// picoseconds of execution time, paying for this with up to `fees` from the Holding Register.
737	///
738	/// - `fees`: The asset(s) to remove from the Holding Register to pay for fees.
739	/// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the
740	///   expected maximum weight of the total XCM to be executed for the
741	///   `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed.
742	///
743	/// Kind: *Command*
744	///
745	/// Errors:
746	#[builder(pays_fees)]
747	BuyExecution { fees: Asset, weight_limit: WeightLimit },
748
749	/// Refund any surplus weight previously bought with `BuyExecution`.
750	///
751	/// Kind: *Command*
752	///
753	/// Errors: None.
754	RefundSurplus,
755
756	/// Set the Error Handler Register. This is code that should be called in the case of an error
757	/// happening.
758	///
759	/// An error occurring within execution of this code will _NOT_ result in the error register
760	/// being set, nor will an error handler be called due to it. The error handler and appendix
761	/// may each still be set.
762	///
763	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
764	/// weight however includes only the difference between the previous handler and the new
765	/// handler, which can reasonably be negative, which would result in a surplus.
766	///
767	/// Kind: *Command*
768	///
769	/// Errors: None.
770	SetErrorHandler(Xcm<Call>),
771
772	/// Set the Appendix Register. This is code that should be called after code execution
773	/// (including the error handler if any) is finished. This will be called regardless of whether
774	/// an error occurred.
775	///
776	/// Any error occurring due to execution of this code will result in the error register being
777	/// set, and the error handler (if set) firing.
778	///
779	/// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing
780	/// weight however includes only the difference between the previous appendix and the new
781	/// appendix, which can reasonably be negative, which would result in a surplus.
782	///
783	/// Kind: *Command*
784	///
785	/// Errors: None.
786	SetAppendix(Xcm<Call>),
787
788	/// Clear the Error Register.
789	///
790	/// Kind: *Command*
791	///
792	/// Errors: None.
793	ClearError,
794
795	/// Create some assets which are being held on behalf of the origin.
796	///
797	/// - `assets`: The assets which are to be claimed. This must match exactly with the assets
798	///   claimable by the origin of the ticket.
799	/// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the
800	///   asset.
801	///
802	/// Kind: *Command*
803	///
804	/// Errors:
805	#[builder(loads_holding)]
806	ClaimAsset { assets: Assets, ticket: Location },
807
808	/// Always throws an error of type `Trap`.
809	///
810	/// Kind: *Command*
811	///
812	/// Errors:
813	/// - `Trap`: All circumstances, whose inner value is the same as this item's inner value.
814	Trap(#[codec(compact)] u64),
815
816	/// Ask the destination system to respond with the most recent version of XCM that they
817	/// support in a `QueryResponse` instruction. Any changes to this should also elicit similar
818	/// responses when they happen.
819	///
820	/// - `query_id`: An identifier that will be replicated into the returned XCM message.
821	/// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which
822	///   is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the
823	///   response may not execute at all.
824	///
825	/// Kind: *Command*
826	///
827	/// Errors: *Fallible*
828	SubscribeVersion {
829		#[codec(compact)]
830		query_id: QueryId,
831		max_response_weight: Weight,
832	},
833
834	/// Cancel the effect of a previous `SubscribeVersion` instruction.
835	///
836	/// Kind: *Command*
837	///
838	/// Errors: *Fallible*
839	UnsubscribeVersion,
840
841	/// Reduce Holding by up to the given assets.
842	///
843	/// Holding is reduced by as much as possible up to the assets in the parameter. It is not an
844	/// error if the Holding does not contain the assets (to make this an error, use `ExpectAsset`
845	/// prior).
846	///
847	/// Kind: *Command*
848	///
849	/// Errors: *Infallible*
850	BurnAsset(Assets),
851
852	/// Throw an error if Holding does not contain at least the given assets.
853	///
854	/// Kind: *Command*
855	///
856	/// Errors:
857	/// - `ExpectationFalse`: If Holding Register does not contain the assets in the parameter.
858	ExpectAsset(Assets),
859
860	/// Ensure that the Origin Register equals some given value and throw an error if not.
861	///
862	/// Kind: *Command*
863	///
864	/// Errors:
865	/// - `ExpectationFalse`: If Origin Register is not equal to the parameter.
866	ExpectOrigin(Option<Location>),
867
868	/// Ensure that the Error Register equals some given value and throw an error if not.
869	///
870	/// Kind: *Command*
871	///
872	/// Errors:
873	/// - `ExpectationFalse`: If the value of the Error Register is not equal to the parameter.
874	ExpectError(Option<(u32, Error)>),
875
876	/// Ensure that the Transact Status Register equals some given value and throw an error if
877	/// not.
878	///
879	/// Kind: *Command*
880	///
881	/// Errors:
882	/// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the
883	///   parameter.
884	ExpectTransactStatus(MaybeErrorCode),
885
886	/// Query the existence of a particular pallet type.
887	///
888	/// - `module_name`: The module name of the pallet to query.
889	/// - `response_info`: Information for making the response.
890	///
891	/// Sends a `QueryResponse` to Origin whose data field `PalletsInfo` containing the information
892	/// of all pallets on the local chain whose name is equal to `name`. This is empty in the case
893	/// that the local chain is not based on Substrate Frame.
894	///
895	/// Safety: No concerns.
896	///
897	/// Kind: *Command*
898	///
899	/// Errors: *Fallible*.
900	QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
901
902	/// Ensure that a particular pallet with a particular version exists.
903	///
904	/// - `index: Compact`: The index which identifies the pallet. An error if no pallet exists at
905	///   this index.
906	/// - `name: Vec<u8>`: Name which must be equal to the name of the pallet.
907	/// - `module_name: Vec<u8>`: Module name which must be equal to the name of the module in
908	///   which the pallet exists.
909	/// - `crate_major: Compact`: Version number which must be equal to the major version of the
910	///   crate which implements the pallet.
911	/// - `min_crate_minor: Compact`: Version number which must be at most the minor version of the
912	///   crate which implements the pallet.
913	///
914	/// Safety: No concerns.
915	///
916	/// Kind: *Command*
917	///
918	/// Errors:
919	/// - `ExpectationFalse`: In case any of the expectations are broken.
920	ExpectPallet {
921		#[codec(compact)]
922		index: u32,
923		name: Vec<u8>,
924		module_name: Vec<u8>,
925		#[codec(compact)]
926		crate_major: u32,
927		#[codec(compact)]
928		min_crate_minor: u32,
929	},
930
931	/// Send a `QueryResponse` message containing the value of the Transact Status Register to some
932	/// destination.
933	///
934	/// - `query_response_info`: The information needed for constructing and sending the
935	///   `QueryResponse` message.
936	///
937	/// Safety: No concerns.
938	///
939	/// Kind: *Command*
940	///
941	/// Errors: *Fallible*.
942	ReportTransactStatus(QueryResponseInfo),
943
944	/// Set the Transact Status Register to its default, cleared, value.
945	///
946	/// Safety: No concerns.
947	///
948	/// Kind: *Command*
949	///
950	/// Errors: *Infallible*.
951	ClearTransactStatus,
952
953	/// Set the Origin Register to be some child of the Universal Ancestor.
954	///
955	/// Safety: Should only be usable if the Origin is trusted to represent the Universal Ancestor
956	/// child in general. In general, no Origin should be able to represent the Universal Ancestor
957	/// child which is the root of the local consensus system since it would by extension
958	/// allow it to act as any location within the local consensus.
959	///
960	/// The `Junction` parameter should generally be a `GlobalConsensus` variant since it is only
961	/// these which are children of the Universal Ancestor.
962	///
963	/// Kind: *Command*
964	///
965	/// Errors: *Fallible*.
966	UniversalOrigin(Junction),
967
968	/// Send a message on to Non-Local Consensus system.
969	///
970	/// This will tend to utilize some extra-consensus mechanism, the obvious one being a bridge.
971	/// A fee may be charged; this may be determined based on the contents of `xcm`. It will be
972	/// taken from the Holding register.
973	///
974	/// - `network`: The remote consensus system to which the message should be exported.
975	/// - `destination`: The location relative to the remote consensus system to which the message
976	///   should be sent on arrival.
977	/// - `xcm`: The message to be exported.
978	///
979	/// As an example, to export a message for execution on Statemine (parachain #1000 in the
980	/// Kusama network), you would call with `network: NetworkId::Kusama` and
981	/// `destination: [Parachain(1000)].into()`. Alternatively, to export a message for execution
982	/// on Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`.
983	///
984	/// Kind: *Command*
985	///
986	/// Errors: *Fallible*.
987	ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> },
988
989	/// Lock the locally held asset and prevent further transfer or withdrawal.
990	///
991	/// This restriction may be removed by the `UnlockAsset` instruction being called with an
992	/// Origin of `unlocker` and a `target` equal to the current `Origin`.
993	///
994	/// If the locking is successful, then a `NoteUnlockable` instruction is sent to `unlocker`.
995	///
996	/// - `asset`: The asset(s) which should be locked.
997	/// - `unlocker`: The value which the Origin must be for a corresponding `UnlockAsset`
998	///   instruction to work.
999	///
1000	/// Kind: *Command*.
1001	///
1002	/// Errors:
1003	LockAsset { asset: Asset, unlocker: Location },
1004
1005	/// Remove the lock over `asset` on this chain and (if nothing else is preventing it) allow the
1006	/// asset to be transferred.
1007	///
1008	/// - `asset`: The asset to be unlocked.
1009	/// - `target`: The owner of the asset on the local chain.
1010	///
1011	/// Safety: No concerns.
1012	///
1013	/// Kind: *Command*.
1014	///
1015	/// Errors:
1016	UnlockAsset { asset: Asset, target: Location },
1017
1018	/// Asset (`asset`) has been locked on the `origin` system and may not be transferred. It may
1019	/// only be unlocked with the receipt of the `UnlockAsset` instruction from this chain.
1020	///
1021	/// - `asset`: The asset(s) which are now unlockable from this origin.
1022	/// - `owner`: The owner of the asset on the chain in which it was locked. This may be a
1023	///   location specific to the origin network.
1024	///
1025	/// Safety: `origin` must be trusted to have locked the corresponding `asset`
1026	/// prior as a consequence of sending this message.
1027	///
1028	/// Kind: *Trusted Indication*.
1029	///
1030	/// Errors:
1031	NoteUnlockable { asset: Asset, owner: Location },
1032
1033	/// Send an `UnlockAsset` instruction to the `locker` for the given `asset`.
1034	///
1035	/// This may fail if the local system is making use of the fact that the asset is locked or,
1036	/// of course, if there is no record that the asset actually is locked.
1037	///
1038	/// - `asset`: The asset(s) to be unlocked.
1039	/// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which an
1040	///   `UnlockAsset` should be sent.
1041	///
1042	/// Kind: *Command*.
1043	///
1044	/// Errors:
1045	RequestUnlock { asset: Asset, locker: Location },
1046
1047	/// Sets the Fees Mode Register.
1048	///
1049	/// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions are
1050	///   withdrawn as needed using the same mechanism as `WithdrawAssets`.
1051	///
1052	/// Kind: *Command*.
1053	///
1054	/// Errors:
1055	SetFeesMode { jit_withdraw: bool },
1056
1057	/// Set the Topic Register.
1058	///
1059	/// The 32-byte array identifier in the parameter is not guaranteed to be
1060	/// unique; if such a property is desired, it is up to the code author to
1061	/// enforce uniqueness.
1062	///
1063	/// Safety: No concerns.
1064	///
1065	/// Kind: *Command*
1066	///
1067	/// Errors:
1068	SetTopic([u8; 32]),
1069
1070	/// Clear the Topic Register.
1071	///
1072	/// Kind: *Command*
1073	///
1074	/// Errors: None.
1075	ClearTopic,
1076
1077	/// Alter the current Origin to another given origin.
1078	///
1079	/// Kind: *Command*
1080	///
1081	/// Errors: If the existing state would not allow such a change.
1082	AliasOrigin(Location),
1083
1084	/// A directive to indicate that the origin expects free execution of the message.
1085	///
1086	/// At execution time, this instruction just does a check on the Origin register.
1087	/// However, at the barrier stage messages starting with this instruction can be disregarded if
1088	/// the origin is not acceptable for free execution or the `weight_limit` is `Limited` and
1089	/// insufficient.
1090	///
1091	/// Kind: *Indication*
1092	///
1093	/// Errors: If the given origin is `Some` and not equal to the current Origin register.
1094	UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<Location> },
1095}
1096
1097impl<Call> Xcm<Call> {
1098	pub fn into<C>(self) -> Xcm<C> {
1099		Xcm::from(self)
1100	}
1101	pub fn from<C>(xcm: Xcm<C>) -> Self {
1102		Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1103	}
1104}
1105
1106impl<Call> Instruction<Call> {
1107	pub fn into<C>(self) -> Instruction<C> {
1108		Instruction::from(self)
1109	}
1110	pub fn from<C>(xcm: Instruction<C>) -> Self {
1111		use Instruction::*;
1112		match xcm {
1113			WithdrawAsset(assets) => WithdrawAsset(assets),
1114			ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1115			ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1116			QueryResponse { query_id, response, max_weight, querier } => {
1117				QueryResponse { query_id, response, max_weight, querier }
1118			},
1119			TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1120			TransferReserveAsset { assets, dest, xcm } => {
1121				TransferReserveAsset { assets, dest, xcm }
1122			},
1123			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1124				HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1125			},
1126			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1127			HrmpChannelClosing { initiator, sender, recipient } => {
1128				HrmpChannelClosing { initiator, sender, recipient }
1129			},
1130			Transact { origin_kind, require_weight_at_most, call } => {
1131				Transact { origin_kind, require_weight_at_most, call: call.into() }
1132			},
1133			ReportError(response_info) => ReportError(response_info),
1134			DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1135			DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1136			ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1137			InitiateReserveWithdraw { assets, reserve, xcm } => {
1138				InitiateReserveWithdraw { assets, reserve, xcm }
1139			},
1140			InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1141			ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1142			BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1143			ClearOrigin => ClearOrigin,
1144			DescendOrigin(who) => DescendOrigin(who),
1145			RefundSurplus => RefundSurplus,
1146			SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1147			SetAppendix(xcm) => SetAppendix(xcm.into()),
1148			ClearError => ClearError,
1149			ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1150			Trap(code) => Trap(code),
1151			SubscribeVersion { query_id, max_response_weight } => {
1152				SubscribeVersion { query_id, max_response_weight }
1153			},
1154			UnsubscribeVersion => UnsubscribeVersion,
1155			BurnAsset(assets) => BurnAsset(assets),
1156			ExpectAsset(assets) => ExpectAsset(assets),
1157			ExpectOrigin(origin) => ExpectOrigin(origin),
1158			ExpectError(error) => ExpectError(error),
1159			ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1160			QueryPallet { module_name, response_info } => {
1161				QueryPallet { module_name, response_info }
1162			},
1163			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1164				ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1165			},
1166			ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1167			ClearTransactStatus => ClearTransactStatus,
1168			UniversalOrigin(j) => UniversalOrigin(j),
1169			ExportMessage { network, destination, xcm } => {
1170				ExportMessage { network, destination, xcm }
1171			},
1172			LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1173			UnlockAsset { asset, target } => UnlockAsset { asset, target },
1174			NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1175			RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1176			SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1177			SetTopic(topic) => SetTopic(topic),
1178			ClearTopic => ClearTopic,
1179			AliasOrigin(location) => AliasOrigin(location),
1180			UnpaidExecution { weight_limit, check_origin } => {
1181				UnpaidExecution { weight_limit, check_origin }
1182			},
1183		}
1184	}
1185}
1186
1187// TODO: Automate Generation
1188impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1189	fn weight(&self) -> Weight {
1190		use Instruction::*;
1191		match self {
1192			WithdrawAsset(assets) => W::withdraw_asset(assets),
1193			ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1194			ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1195			QueryResponse { query_id, response, max_weight, querier } => {
1196				W::query_response(query_id, response, max_weight, querier)
1197			},
1198			TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1199			TransferReserveAsset { assets, dest, xcm } => {
1200				W::transfer_reserve_asset(&assets, dest, xcm)
1201			},
1202			Transact { origin_kind, require_weight_at_most, call } => {
1203				W::transact(origin_kind, require_weight_at_most, call)
1204			},
1205			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1206				W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity)
1207			},
1208			HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1209			HrmpChannelClosing { initiator, sender, recipient } => {
1210				W::hrmp_channel_closing(initiator, sender, recipient)
1211			},
1212			ClearOrigin => W::clear_origin(),
1213			DescendOrigin(who) => W::descend_origin(who),
1214			ReportError(response_info) => W::report_error(&response_info),
1215			DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1216			DepositReserveAsset { assets, dest, xcm } => {
1217				W::deposit_reserve_asset(assets, dest, xcm)
1218			},
1219			ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1220			InitiateReserveWithdraw { assets, reserve, xcm } => {
1221				W::initiate_reserve_withdraw(assets, reserve, xcm)
1222			},
1223			InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1224			ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1225			BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1226			RefundSurplus => W::refund_surplus(),
1227			SetErrorHandler(xcm) => W::set_error_handler(xcm),
1228			SetAppendix(xcm) => W::set_appendix(xcm),
1229			ClearError => W::clear_error(),
1230			ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1231			Trap(code) => W::trap(code),
1232			SubscribeVersion { query_id, max_response_weight } => {
1233				W::subscribe_version(query_id, max_response_weight)
1234			},
1235			UnsubscribeVersion => W::unsubscribe_version(),
1236			BurnAsset(assets) => W::burn_asset(assets),
1237			ExpectAsset(assets) => W::expect_asset(assets),
1238			ExpectOrigin(origin) => W::expect_origin(origin),
1239			ExpectError(error) => W::expect_error(error),
1240			ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1241			QueryPallet { module_name, response_info } => {
1242				W::query_pallet(module_name, response_info)
1243			},
1244			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1245				W::expect_pallet(index, name, module_name, crate_major, min_crate_minor)
1246			},
1247			ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1248			ClearTransactStatus => W::clear_transact_status(),
1249			UniversalOrigin(j) => W::universal_origin(j),
1250			ExportMessage { network, destination, xcm } => {
1251				W::export_message(network, destination, xcm)
1252			},
1253			LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1254			UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1255			NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1256			RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1257			SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1258			SetTopic(topic) => W::set_topic(topic),
1259			ClearTopic => W::clear_topic(),
1260			AliasOrigin(location) => W::alias_origin(location),
1261			UnpaidExecution { weight_limit, check_origin } => {
1262				W::unpaid_execution(weight_limit, check_origin)
1263			},
1264		}
1265	}
1266}
1267
1268pub mod opaque {
1269	/// The basic concrete type of `Xcm`, which doesn't make any assumptions about the
1270	/// format of a call other than it is pre-encoded.
1271	pub type Xcm = super::Xcm<()>;
1272
1273	/// The basic concrete type of `Instruction`, which doesn't make any assumptions about the
1274	/// format of a call other than it is pre-encoded.
1275	pub type Instruction = super::Instruction<()>;
1276}
1277
1278// Convert from a v3 XCM to a v4 XCM
1279impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
1280	type Error = ();
1281	fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, Self::Error> {
1282		Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1283	}
1284}
1285
1286// Convert from a v5 XCM to a v4 XCM.
1287impl<Call: Decode + GetDispatchInfo> TryFrom<NewXcm<Call>> for Xcm<Call> {
1288	type Error = ();
1289	fn try_from(new_xcm: NewXcm<Call>) -> result::Result<Self, Self::Error> {
1290		Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1291	}
1292}
1293
1294// Convert from a v5 instruction to a v4 instruction.
1295impl<Call: Decode + GetDispatchInfo> TryFrom<NewInstruction<Call>> for Instruction<Call> {
1296	type Error = ();
1297	fn try_from(new_instruction: NewInstruction<Call>) -> result::Result<Self, Self::Error> {
1298		use NewInstruction::*;
1299		Ok(match new_instruction {
1300			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1301			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1302			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1303			QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1304				Self::QueryResponse {
1305					query_id,
1306					querier: querier.try_into()?,
1307					response: response.try_into()?,
1308					max_weight,
1309				}
1310			},
1311			QueryResponse { query_id, response, max_weight, querier: None } => {
1312				Self::QueryResponse {
1313					query_id,
1314					querier: None,
1315					response: response.try_into()?,
1316					max_weight,
1317				}
1318			},
1319			TransferAsset { assets, beneficiary } => Self::TransferAsset {
1320				assets: assets.try_into()?,
1321				beneficiary: beneficiary.try_into()?,
1322			},
1323			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1324				assets: assets.try_into()?,
1325				dest: dest.try_into()?,
1326				xcm: xcm.try_into()?,
1327			},
1328			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1329				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1330			},
1331			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1332			HrmpChannelClosing { initiator, sender, recipient } => {
1333				Self::HrmpChannelClosing { initiator, sender, recipient }
1334			},
1335			Transact { origin_kind, mut call, fallback_max_weight } => {
1336				// We first try to decode the call, if we can't, we use the fallback weight,
1337				// if there's no fallback, we just return `Weight::MAX`.
1338				let require_weight_at_most = match call.take_decoded() {
1339					Ok(decoded) => decoded.get_dispatch_info().call_weight,
1340					Err(error) => {
1341						let fallback_weight = fallback_max_weight.unwrap_or(Weight::MAX);
1342						tracing::debug!(
1343							target: "xcm::versions::v5Tov4",
1344							?error,
1345							?fallback_weight,
1346							"Couldn't decode call in Transact"
1347						);
1348						fallback_weight
1349					},
1350				};
1351				Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1352			},
1353			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1354				query_id: response_info.query_id,
1355				destination: response_info.destination.try_into().map_err(|_| ())?,
1356				max_weight: response_info.max_weight,
1357			}),
1358			DepositAsset { assets, beneficiary } => {
1359				let beneficiary = beneficiary.try_into()?;
1360				let assets = assets.try_into()?;
1361				Self::DepositAsset { assets, beneficiary }
1362			},
1363			DepositReserveAsset { assets, dest, xcm } => {
1364				let dest = dest.try_into()?;
1365				let xcm = xcm.try_into()?;
1366				let assets = assets.try_into()?;
1367				Self::DepositReserveAsset { assets, dest, xcm }
1368			},
1369			ExchangeAsset { give, want, maximal } => {
1370				let give = give.try_into()?;
1371				let want = want.try_into()?;
1372				Self::ExchangeAsset { give, want, maximal }
1373			},
1374			InitiateReserveWithdraw { assets, reserve, xcm } => {
1375				// No `max_assets` here, so if there's a connt, then we cannot translate.
1376				let assets = assets.try_into()?;
1377				let reserve = reserve.try_into()?;
1378				let xcm = xcm.try_into()?;
1379				Self::InitiateReserveWithdraw { assets, reserve, xcm }
1380			},
1381			InitiateTeleport { assets, dest, xcm } => {
1382				// No `max_assets` here, so if there's a connt, then we cannot translate.
1383				let assets = assets.try_into()?;
1384				let dest = dest.try_into()?;
1385				let xcm = xcm.try_into()?;
1386				Self::InitiateTeleport { assets, dest, xcm }
1387			},
1388			ReportHolding { response_info, assets } => {
1389				let response_info = QueryResponseInfo {
1390					destination: response_info.destination.try_into().map_err(|_| ())?,
1391					query_id: response_info.query_id,
1392					max_weight: response_info.max_weight,
1393				};
1394				Self::ReportHolding { response_info, assets: assets.try_into()? }
1395			},
1396			BuyExecution { fees, weight_limit } => {
1397				let fees = fees.try_into()?;
1398				let weight_limit = weight_limit.into();
1399				Self::BuyExecution { fees, weight_limit }
1400			},
1401			ClearOrigin => Self::ClearOrigin,
1402			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1403			RefundSurplus => Self::RefundSurplus,
1404			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1405			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1406			ClearError => Self::ClearError,
1407			ClaimAsset { assets, ticket } => {
1408				let assets = assets.try_into()?;
1409				let ticket = ticket.try_into()?;
1410				Self::ClaimAsset { assets, ticket }
1411			},
1412			Trap(code) => Self::Trap(code),
1413			SubscribeVersion { query_id, max_response_weight } => {
1414				Self::SubscribeVersion { query_id, max_response_weight }
1415			},
1416			UnsubscribeVersion => Self::UnsubscribeVersion,
1417			BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1418			ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1419			ExpectOrigin(maybe_origin) => {
1420				Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?)
1421			},
1422			ExpectError(maybe_error) => Self::ExpectError(
1423				maybe_error
1424					.map(|(num, new_error)| (num, new_error.try_into()))
1425					.map(|(num, result)| result.map(|inner| (num, inner)))
1426					.transpose()?,
1427			),
1428			ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1429			QueryPallet { module_name, response_info } => {
1430				Self::QueryPallet { module_name, response_info: response_info.try_into()? }
1431			},
1432			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1433				Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1434			},
1435			ReportTransactStatus(response_info) => {
1436				Self::ReportTransactStatus(response_info.try_into()?)
1437			},
1438			ClearTransactStatus => Self::ClearTransactStatus,
1439			UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?),
1440			ExportMessage { network, destination, xcm } => Self::ExportMessage {
1441				network: network.into(),
1442				destination: destination.try_into()?,
1443				xcm: xcm.try_into()?,
1444			},
1445			LockAsset { asset, unlocker } => {
1446				Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? }
1447			},
1448			UnlockAsset { asset, target } => {
1449				Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? }
1450			},
1451			NoteUnlockable { asset, owner } => {
1452				Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? }
1453			},
1454			RequestUnlock { asset, locker } => {
1455				Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? }
1456			},
1457			SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1458			SetTopic(topic) => Self::SetTopic(topic),
1459			ClearTopic => Self::ClearTopic,
1460			AliasOrigin(location) => Self::AliasOrigin(location.try_into()?),
1461			UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1462				weight_limit,
1463				check_origin: check_origin.map(|origin| origin.try_into()).transpose()?,
1464			},
1465			InitiateTransfer { .. } |
1466			PayFees { .. } |
1467			SetHints { .. } |
1468			ExecuteWithOrigin { .. } => {
1469				tracing::debug!(target: "xcm::versions::v5tov4", ?new_instruction, "not supported by v4");
1470				return Err(());
1471			},
1472		})
1473	}
1474}
1475
1476// Convert from a v3 instruction to a v4 instruction
1477impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
1478	type Error = ();
1479	fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, Self::Error> {
1480		use OldInstruction::*;
1481		Ok(match old_instruction {
1482			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1483			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1484			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1485			QueryResponse { query_id, response, max_weight, querier: Some(querier) } => {
1486				Self::QueryResponse {
1487					query_id,
1488					querier: querier.try_into()?,
1489					response: response.try_into()?,
1490					max_weight,
1491				}
1492			},
1493			QueryResponse { query_id, response, max_weight, querier: None } => {
1494				Self::QueryResponse {
1495					query_id,
1496					querier: None,
1497					response: response.try_into()?,
1498					max_weight,
1499				}
1500			},
1501			TransferAsset { assets, beneficiary } => Self::TransferAsset {
1502				assets: assets.try_into()?,
1503				beneficiary: beneficiary.try_into()?,
1504			},
1505			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1506				assets: assets.try_into()?,
1507				dest: dest.try_into()?,
1508				xcm: xcm.try_into()?,
1509			},
1510			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => {
1511				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }
1512			},
1513			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1514			HrmpChannelClosing { initiator, sender, recipient } => {
1515				Self::HrmpChannelClosing { initiator, sender, recipient }
1516			},
1517			Transact { origin_kind, require_weight_at_most, call } => {
1518				Self::Transact { origin_kind, require_weight_at_most, call: call.into() }
1519			},
1520			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1521				query_id: response_info.query_id,
1522				destination: response_info.destination.try_into().map_err(|_| ())?,
1523				max_weight: response_info.max_weight,
1524			}),
1525			DepositAsset { assets, beneficiary } => {
1526				let beneficiary = beneficiary.try_into()?;
1527				let assets = assets.try_into()?;
1528				Self::DepositAsset { assets, beneficiary }
1529			},
1530			DepositReserveAsset { assets, dest, xcm } => {
1531				let dest = dest.try_into()?;
1532				let xcm = xcm.try_into()?;
1533				let assets = assets.try_into()?;
1534				Self::DepositReserveAsset { assets, dest, xcm }
1535			},
1536			ExchangeAsset { give, want, maximal } => {
1537				let give = give.try_into()?;
1538				let want = want.try_into()?;
1539				Self::ExchangeAsset { give, want, maximal }
1540			},
1541			InitiateReserveWithdraw { assets, reserve, xcm } => {
1542				let assets = assets.try_into()?;
1543				let reserve = reserve.try_into()?;
1544				let xcm = xcm.try_into()?;
1545				Self::InitiateReserveWithdraw { assets, reserve, xcm }
1546			},
1547			InitiateTeleport { assets, dest, xcm } => {
1548				let assets = assets.try_into()?;
1549				let dest = dest.try_into()?;
1550				let xcm = xcm.try_into()?;
1551				Self::InitiateTeleport { assets, dest, xcm }
1552			},
1553			ReportHolding { response_info, assets } => {
1554				let response_info = QueryResponseInfo {
1555					destination: response_info.destination.try_into().map_err(|_| ())?,
1556					query_id: response_info.query_id,
1557					max_weight: response_info.max_weight,
1558				};
1559				Self::ReportHolding { response_info, assets: assets.try_into()? }
1560			},
1561			BuyExecution { fees, weight_limit } => {
1562				let fees = fees.try_into()?;
1563				let weight_limit = weight_limit.into();
1564				Self::BuyExecution { fees, weight_limit }
1565			},
1566			ClearOrigin => Self::ClearOrigin,
1567			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1568			RefundSurplus => Self::RefundSurplus,
1569			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1570			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1571			ClearError => Self::ClearError,
1572			ClaimAsset { assets, ticket } => {
1573				let assets = assets.try_into()?;
1574				let ticket = ticket.try_into()?;
1575				Self::ClaimAsset { assets, ticket }
1576			},
1577			Trap(code) => Self::Trap(code),
1578			SubscribeVersion { query_id, max_response_weight } => {
1579				Self::SubscribeVersion { query_id, max_response_weight }
1580			},
1581			UnsubscribeVersion => Self::UnsubscribeVersion,
1582			BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1583			ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1584			ExpectOrigin(maybe_location) => Self::ExpectOrigin(
1585				maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?,
1586			),
1587			ExpectError(maybe_error) => Self::ExpectError(
1588				maybe_error.map(|error| error.try_into()).transpose().map_err(|_| ())?,
1589			),
1590			ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1591			QueryPallet { module_name, response_info } => Self::QueryPallet {
1592				module_name,
1593				response_info: response_info.try_into().map_err(|_| ())?,
1594			},
1595			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => {
1596				Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }
1597			},
1598			ReportTransactStatus(response_info) => {
1599				Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?)
1600			},
1601			ClearTransactStatus => Self::ClearTransactStatus,
1602			UniversalOrigin(junction) => {
1603				Self::UniversalOrigin(junction.try_into().map_err(|_| ())?)
1604			},
1605			ExportMessage { network, destination, xcm } => Self::ExportMessage {
1606				network: network.into(),
1607				destination: destination.try_into().map_err(|_| ())?,
1608				xcm: xcm.try_into().map_err(|_| ())?,
1609			},
1610			LockAsset { asset, unlocker } => Self::LockAsset {
1611				asset: asset.try_into().map_err(|_| ())?,
1612				unlocker: unlocker.try_into().map_err(|_| ())?,
1613			},
1614			UnlockAsset { asset, target } => Self::UnlockAsset {
1615				asset: asset.try_into().map_err(|_| ())?,
1616				target: target.try_into().map_err(|_| ())?,
1617			},
1618			NoteUnlockable { asset, owner } => Self::NoteUnlockable {
1619				asset: asset.try_into().map_err(|_| ())?,
1620				owner: owner.try_into().map_err(|_| ())?,
1621			},
1622			RequestUnlock { asset, locker } => Self::RequestUnlock {
1623				asset: asset.try_into().map_err(|_| ())?,
1624				locker: locker.try_into().map_err(|_| ())?,
1625			},
1626			SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1627			SetTopic(topic) => Self::SetTopic(topic),
1628			ClearTopic => Self::ClearTopic,
1629			AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?),
1630			UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1631				weight_limit,
1632				check_origin: check_origin
1633					.map(|location| location.try_into())
1634					.transpose()
1635					.map_err(|_| ())?,
1636			},
1637		})
1638	}
1639}
1640
1641#[cfg(test)]
1642mod tests {
1643	use super::{prelude::*, *};
1644	use crate::{
1645		v3::{
1646			Junctions::Here as OldHere, MultiAssetFilter as OldMultiAssetFilter,
1647			WildMultiAsset as OldWildMultiAsset,
1648		},
1649		MAX_INSTRUCTIONS_TO_DECODE,
1650	};
1651
1652	#[test]
1653	fn basic_roundtrip_works() {
1654		let xcm = Xcm::<()>(vec![TransferAsset {
1655			assets: (Here, 1u128).into(),
1656			beneficiary: Here.into(),
1657		}]);
1658		let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset {
1659			assets: (OldHere, 1u128).into(),
1660			beneficiary: OldHere.into(),
1661		}]);
1662		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1663		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1664		assert_eq!(new_xcm, xcm);
1665	}
1666
1667	#[test]
1668	fn teleport_roundtrip_works() {
1669		let xcm = Xcm::<()>(vec![
1670			ReceiveTeleportedAsset((Here, 1u128).into()),
1671			ClearOrigin,
1672			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1673		]);
1674		let old_xcm: OldXcm<()> = OldXcm::<()>(vec![
1675			OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()),
1676			OldInstruction::ClearOrigin,
1677			OldInstruction::DepositAsset {
1678				assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1679				beneficiary: OldHere.into(),
1680			},
1681		]);
1682		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1683		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1684		assert_eq!(new_xcm, xcm);
1685	}
1686
1687	#[test]
1688	fn reserve_deposit_roundtrip_works() {
1689		let xcm = Xcm::<()>(vec![
1690			ReserveAssetDeposited((Here, 1u128).into()),
1691			ClearOrigin,
1692			BuyExecution {
1693				fees: (Here, 1u128).into(),
1694				weight_limit: Some(Weight::from_parts(1, 1)).into(),
1695			},
1696			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1697		]);
1698		let old_xcm = OldXcm::<()>(vec![
1699			OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()),
1700			OldInstruction::ClearOrigin,
1701			OldInstruction::BuyExecution {
1702				fees: (OldHere, 1u128).into(),
1703				weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)),
1704			},
1705			OldInstruction::DepositAsset {
1706				assets: crate::v3::MultiAssetFilter::Wild(crate::v3::WildMultiAsset::AllCounted(1)),
1707				beneficiary: OldHere.into(),
1708			},
1709		]);
1710		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1711		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1712		assert_eq!(new_xcm, xcm);
1713	}
1714
1715	#[test]
1716	fn deposit_asset_roundtrip_works() {
1717		let xcm = Xcm::<()>(vec![
1718			WithdrawAsset((Here, 1u128).into()),
1719			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1720		]);
1721		let old_xcm = OldXcm::<()>(vec![
1722			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1723			OldInstruction::DepositAsset {
1724				assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1725				beneficiary: OldHere.into(),
1726			},
1727		]);
1728		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1729		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1730		assert_eq!(new_xcm, xcm);
1731	}
1732
1733	#[test]
1734	fn deposit_reserve_asset_roundtrip_works() {
1735		let xcm = Xcm::<()>(vec![
1736			WithdrawAsset((Here, 1u128).into()),
1737			DepositReserveAsset {
1738				assets: Wild(AllCounted(1)),
1739				dest: Here.into(),
1740				xcm: Xcm::<()>(vec![]),
1741			},
1742		]);
1743		let old_xcm = OldXcm::<()>(vec![
1744			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1745			OldInstruction::DepositReserveAsset {
1746				assets: OldMultiAssetFilter::Wild(OldWildMultiAsset::AllCounted(1)),
1747				dest: OldHere.into(),
1748				xcm: OldXcm::<()>(vec![]),
1749			},
1750		]);
1751		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1752		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1753		assert_eq!(new_xcm, xcm);
1754	}
1755
1756	#[test]
1757	fn decoding_respects_limit() {
1758		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1759		let encoded = max_xcm.encode();
1760		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1761
1762		let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1763		let encoded = big_xcm.encode();
1764		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1765
1766		let nested_xcm = Xcm::<()>(vec![
1767			DepositReserveAsset {
1768				assets: All.into(),
1769				dest: Here.into(),
1770				xcm: max_xcm,
1771			};
1772			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1773		]);
1774		let encoded = nested_xcm.encode();
1775		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1776
1777		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1778		let encoded = even_more_nested_xcm.encode();
1779		assert_eq!(encoded.len(), 342530);
1780		// This should not decode since the limit is 100
1781		assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1782		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1783	}
1784}