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