referrerpolicy=no-referrer-when-downgrade

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