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