1pub use super::v3::GetWeight;
20use super::v4::{
21	Instruction as OldInstruction, PalletInfo as OldPalletInfo,
22	QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm,
23};
24use crate::{utils::decode_xcm_instructions, DoubleEncoded};
25use alloc::{vec, vec::Vec};
26use bounded_collections::{parameter_types, BoundedVec};
27use codec::{
28	self, Decode, DecodeWithMemTracking, Encode, Error as CodecError, Input as CodecInput,
29	MaxEncodedLen,
30};
31use core::{fmt::Debug, result};
32use derive_where::derive_where;
33use scale_info::TypeInfo;
34
35mod asset;
36mod junction;
37pub(crate) mod junctions;
38mod location;
39mod traits;
40
41pub use asset::{
42	Asset, AssetFilter, AssetId, AssetInstance, AssetTransferFilter, Assets, Fungibility,
43	WildAsset, WildFungibility, MAX_ITEMS_IN_ASSETS,
44};
45pub use junction::{
46	BodyId, BodyPart, Junction, NetworkId, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH,
47};
48pub use junctions::Junctions;
49pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen};
50pub use traits::{
51	send_xcm, validate_send, Error, ExecuteXcm, InstructionError, InstructionIndex, Outcome,
52	PreparedMessage, Reanchorable, Result, SendError, SendResult, SendXcm, Weight, XcmHash,
53};
54pub use super::v4::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit};
56
57pub const VERSION: super::Version = 5;
58
59pub type QueryId = u64;
61
62#[derive(Default, DecodeWithMemTracking, Encode, TypeInfo)]
63#[derive_where(Clone, Eq, PartialEq, Debug)]
64#[codec(encode_bound())]
65#[codec(decode_bound())]
66#[scale_info(bounds(), skip_type_params(Call))]
67pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
68
69impl<Call> Decode for Xcm<Call> {
70	fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
71		Ok(Xcm(decode_xcm_instructions(input)?))
72	}
73}
74
75impl<Call> Xcm<Call> {
76	pub fn new() -> Self {
78		Self(vec![])
79	}
80
81	pub fn is_empty(&self) -> bool {
83		self.0.is_empty()
84	}
85
86	pub fn len(&self) -> usize {
88		self.0.len()
89	}
90
91	pub fn inner(&self) -> &[Instruction<Call>] {
93		&self.0
94	}
95
96	pub fn inner_mut(&mut self) -> &mut Vec<Instruction<Call>> {
98		&mut self.0
99	}
100
101	pub fn into_inner(self) -> Vec<Instruction<Call>> {
103		self.0
104	}
105
106	pub fn iter(&self) -> impl Iterator<Item = &Instruction<Call>> {
108		self.0.iter()
109	}
110
111	pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction<Call>> {
113		self.0.iter_mut()
114	}
115
116	pub fn into_iter(self) -> impl Iterator<Item = Instruction<Call>> {
118		self.0.into_iter()
119	}
120
121	pub fn or_else(self, f: impl FnOnce() -> Self) -> Self {
124		if self.0.is_empty() {
125			f()
126		} else {
127			self
128		}
129	}
130
131	pub fn first(&self) -> Option<&Instruction<Call>> {
133		self.0.first()
134	}
135
136	pub fn last(&self) -> Option<&Instruction<Call>> {
138		self.0.last()
139	}
140
141	pub fn only(&self) -> Option<&Instruction<Call>> {
143		if self.0.len() == 1 {
144			self.0.first()
145		} else {
146			None
147		}
148	}
149
150	pub fn into_only(mut self) -> core::result::Result<Instruction<Call>, Self> {
153		if self.0.len() == 1 {
154			self.0.pop().ok_or(self)
155		} else {
156			Err(self)
157		}
158	}
159}
160
161impl<Call> From<Vec<Instruction<Call>>> for Xcm<Call> {
162	fn from(c: Vec<Instruction<Call>>) -> Self {
163		Self(c)
164	}
165}
166
167impl<Call> From<Xcm<Call>> for Vec<Instruction<Call>> {
168	fn from(c: Xcm<Call>) -> Self {
169		c.0
170	}
171}
172
173pub mod prelude {
175	mod contents {
176		pub use super::super::{
177			send_xcm, validate_send, Ancestor, AncestorThen, Asset,
178			AssetFilter::{self, *},
179			AssetId,
180			AssetInstance::{self, *},
181			Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm,
182			Fungibility::{self, *},
183			Hint::{self, *},
184			HintNumVariants,
185			Instruction::*,
186			InstructionError, InstructionIndex, InteriorLocation,
187			Junction::{self, *},
188			Junctions::{self, Here},
189			Location, MaxAssetTransferFilters, MaybeErrorCode,
190			NetworkId::{self, *},
191			OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
192			QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult,
193			SendXcm, Weight,
194			WeightLimit::{self, *},
195			WildAsset::{self, *},
196			WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
197			XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
198		};
199	}
200	pub use super::{Instruction, Xcm};
201	pub use contents::*;
202	pub mod opaque {
203		pub use super::{
204			super::opaque::{Instruction, Xcm},
205			contents::*,
206		};
207	}
208}
209
210parameter_types! {
211	pub MaxPalletNameLen: u32 = 48;
212	pub MaxPalletsInfo: u32 = 64;
213	pub MaxAssetTransferFilters: u32 = 6;
214}
215
216#[derive(
217	Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
218)]
219pub struct PalletInfo {
220	#[codec(compact)]
221	pub index: u32,
222	pub name: BoundedVec<u8, MaxPalletNameLen>,
223	pub module_name: BoundedVec<u8, MaxPalletNameLen>,
224	#[codec(compact)]
225	pub major: u32,
226	#[codec(compact)]
227	pub minor: u32,
228	#[codec(compact)]
229	pub patch: u32,
230}
231
232impl TryInto<OldPalletInfo> for PalletInfo {
233	type Error = ();
234
235	fn try_into(self) -> result::Result<OldPalletInfo, Self::Error> {
236		OldPalletInfo::new(
237			self.index,
238			self.name.into_inner(),
239			self.module_name.into_inner(),
240			self.major,
241			self.minor,
242			self.patch,
243		)
244		.map_err(|_| ())
245	}
246}
247
248impl PalletInfo {
249	pub fn new(
250		index: u32,
251		name: Vec<u8>,
252		module_name: Vec<u8>,
253		major: u32,
254		minor: u32,
255		patch: u32,
256	) -> result::Result<Self, Error> {
257		let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?;
258		let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?;
259
260		Ok(Self { index, name, module_name, major, minor, patch })
261	}
262}
263
264#[derive(
266	Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo, MaxEncodedLen,
267)]
268pub enum Response {
269	Null,
271	Assets(Assets),
273	ExecutionResult(Option<(u32, Error)>),
275	Version(super::Version),
277	PalletsInfo(BoundedVec<PalletInfo, MaxPalletsInfo>),
279	DispatchResult(MaybeErrorCode),
281}
282
283impl Default for Response {
284	fn default() -> Self {
285		Self::Null
286	}
287}
288
289impl TryFrom<OldResponse> for Response {
290	type Error = ();
291
292	fn try_from(old: OldResponse) -> result::Result<Self, Self::Error> {
293		use OldResponse::*;
294		Ok(match old {
295			Null => Self::Null,
296			Assets(assets) => Self::Assets(assets.try_into()?),
297			ExecutionResult(result) => Self::ExecutionResult(
298				result
299					.map(|(num, old_error)| (num, old_error.try_into()))
300					.map(|(num, result)| result.map(|inner| (num, inner)))
301					.transpose()?,
302			),
303			Version(version) => Self::Version(version),
304			PalletsInfo(pallet_info) => {
305				let inner = pallet_info
306					.into_iter()
307					.map(TryInto::try_into)
308					.collect::<result::Result<Vec<_>, _>>()?;
309				Self::PalletsInfo(
310					BoundedVec::<PalletInfo, MaxPalletsInfo>::try_from(inner).map_err(|_| ())?,
311				)
312			},
313			DispatchResult(maybe_error) => Self::DispatchResult(maybe_error),
314		})
315	}
316}
317
318#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo)]
320pub struct QueryResponseInfo {
321	pub destination: Location,
323	#[codec(compact)]
325	pub query_id: QueryId,
326	pub max_weight: Weight,
328}
329
330impl TryFrom<OldQueryResponseInfo> for QueryResponseInfo {
331	type Error = ();
332
333	fn try_from(old: OldQueryResponseInfo) -> result::Result<Self, Self::Error> {
334		Ok(Self {
335			destination: old.destination.try_into()?,
336			query_id: old.query_id,
337			max_weight: old.max_weight,
338		})
339	}
340}
341
342#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
344pub struct XcmContext {
345	pub origin: Option<Location>,
347	pub message_id: XcmHash,
350	pub topic: Option<[u8; 32]>,
352}
353
354impl XcmContext {
355	pub fn with_message_id(message_id: XcmHash) -> XcmContext {
358		XcmContext { origin: None, message_id, topic: None }
359	}
360
361	pub fn topic_or_message_id(&self) -> XcmHash {
363		if let Some(id) = self.topic {
364			id.into()
365		} else {
366			self.message_id
367		}
368	}
369}
370
371#[derive(
380	Encode,
381	Decode,
382	DecodeWithMemTracking,
383	TypeInfo,
384	xcm_procedural::XcmWeightInfoTrait,
385	xcm_procedural::Builder,
386)]
387#[derive_where(Clone, Eq, PartialEq, Debug)]
388#[codec(encode_bound())]
389#[codec(decode_bound())]
390#[codec(decode_with_mem_tracking_bound())]
391#[scale_info(bounds(), skip_type_params(Call))]
392pub enum Instruction<Call> {
393	#[builder(loads_holding)]
402	WithdrawAsset(Assets),
403
404	#[builder(loads_holding)]
416	ReserveAssetDeposited(Assets),
417
418	#[builder(loads_holding)]
430	ReceiveTeleportedAsset(Assets),
431
432	QueryResponse {
450		#[codec(compact)]
451		query_id: QueryId,
452		response: Response,
453		max_weight: Weight,
454		querier: Option<Location>,
455	},
456
457	TransferAsset { assets: Assets, beneficiary: Location },
469
470	TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> },
489
490	Transact {
508		origin_kind: OriginKind,
509		fallback_max_weight: Option<Weight>,
510		call: DoubleEncoded<Call>,
511	},
512
513	HrmpNewChannelOpenRequest {
525		#[codec(compact)]
526		sender: u32,
527		#[codec(compact)]
528		max_message_size: u32,
529		#[codec(compact)]
530		max_capacity: u32,
531	},
532
533	HrmpChannelAccepted {
543		#[codec(compact)]
546		recipient: u32,
547	},
548
549	HrmpChannelClosing {
560		#[codec(compact)]
561		initiator: u32,
562		#[codec(compact)]
563		sender: u32,
564		#[codec(compact)]
565		recipient: u32,
566	},
567
568	ClearOrigin,
580
581	DescendOrigin(InteriorLocation),
587
588	ReportError(QueryResponseInfo),
598
599	DepositAsset { assets: AssetFilter, beneficiary: Location },
609
610	DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
627
628	ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool },
644
645	InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> },
660
661	InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> },
676
677	ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter },
690
691	#[builder(pays_fees)]
703	BuyExecution { fees: Asset, weight_limit: WeightLimit },
704
705	RefundSurplus,
711
712	SetErrorHandler(Xcm<Call>),
727
728	SetAppendix(Xcm<Call>),
743
744	ClearError,
750
751	#[builder(loads_holding)]
762	ClaimAsset { assets: Assets, ticket: Location },
763
764	Trap(#[codec(compact)] u64),
771
772	SubscribeVersion {
785		#[codec(compact)]
786		query_id: QueryId,
787		max_response_weight: Weight,
788	},
789
790	UnsubscribeVersion,
796
797	BurnAsset(Assets),
807
808	ExpectAsset(Assets),
815
816	ExpectOrigin(Option<Location>),
823
824	ExpectError(Option<(u32, Error)>),
831
832	ExpectTransactStatus(MaybeErrorCode),
841
842	QueryPallet { module_name: Vec<u8>, response_info: QueryResponseInfo },
857
858	ExpectPallet {
877		#[codec(compact)]
878		index: u32,
879		name: Vec<u8>,
880		module_name: Vec<u8>,
881		#[codec(compact)]
882		crate_major: u32,
883		#[codec(compact)]
884		min_crate_minor: u32,
885	},
886
887	ReportTransactStatus(QueryResponseInfo),
899
900	ClearTransactStatus,
908
909	UniversalOrigin(Junction),
923
924	ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> },
944
945	LockAsset { asset: Asset, unlocker: Location },
960
961	UnlockAsset { asset: Asset, target: Location },
973
974	NoteUnlockable { asset: Asset, owner: Location },
988
989	RequestUnlock { asset: Asset, locker: Location },
1002
1003	SetFeesMode { jit_withdraw: bool },
1012
1013	SetTopic([u8; 32]),
1025
1026	ClearTopic,
1032
1033	AliasOrigin(Location),
1039
1040	UnpaidExecution { weight_limit: WeightLimit, check_origin: Option<Location> },
1051
1052	#[builder(pays_fees)]
1058	PayFees { asset: Asset },
1059
1060	InitiateTransfer {
1107		destination: Location,
1108		remote_fees: Option<AssetTransferFilter>,
1109		preserve_origin: bool,
1110		assets: BoundedVec<AssetTransferFilter, MaxAssetTransferFilters>,
1111		remote_xcm: Xcm<()>,
1112	},
1113
1114	ExecuteWithOrigin { descendant_origin: Option<InteriorLocation>, xcm: Xcm<Call> },
1132
1133	SetHints { hints: BoundedVec<Hint, HintNumVariants> },
1142}
1143
1144#[derive(
1145	Encode,
1146	Decode,
1147	DecodeWithMemTracking,
1148	TypeInfo,
1149	Debug,
1150	PartialEq,
1151	Eq,
1152	Clone,
1153	xcm_procedural::NumVariants,
1154)]
1155pub enum Hint {
1156	AssetClaimer { location: Location },
1161}
1162
1163impl<Call> Xcm<Call> {
1164	pub fn into<C>(self) -> Xcm<C> {
1165		Xcm::from(self)
1166	}
1167	pub fn from<C>(xcm: Xcm<C>) -> Self {
1168		Self(xcm.0.into_iter().map(Instruction::<Call>::from).collect())
1169	}
1170}
1171
1172impl<Call> Instruction<Call> {
1173	pub fn into<C>(self) -> Instruction<C> {
1174		Instruction::from(self)
1175	}
1176	pub fn from<C>(xcm: Instruction<C>) -> Self {
1177		use Instruction::*;
1178		match xcm {
1179			WithdrawAsset(assets) => WithdrawAsset(assets),
1180			ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets),
1181			ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets),
1182			QueryResponse { query_id, response, max_weight, querier } =>
1183				QueryResponse { query_id, response, max_weight, querier },
1184			TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary },
1185			TransferReserveAsset { assets, dest, xcm } =>
1186				TransferReserveAsset { assets, dest, xcm },
1187			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1188				HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1189			HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
1190			HrmpChannelClosing { initiator, sender, recipient } =>
1191				HrmpChannelClosing { initiator, sender, recipient },
1192			Transact { origin_kind, call, fallback_max_weight } =>
1193				Transact { origin_kind, call: call.into(), fallback_max_weight },
1194			ReportError(response_info) => ReportError(response_info),
1195			DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary },
1196			DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm },
1197			ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal },
1198			InitiateReserveWithdraw { assets, reserve, xcm } =>
1199				InitiateReserveWithdraw { assets, reserve, xcm },
1200			InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm },
1201			ReportHolding { response_info, assets } => ReportHolding { response_info, assets },
1202			BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit },
1203			ClearOrigin => ClearOrigin,
1204			DescendOrigin(who) => DescendOrigin(who),
1205			RefundSurplus => RefundSurplus,
1206			SetErrorHandler(xcm) => SetErrorHandler(xcm.into()),
1207			SetAppendix(xcm) => SetAppendix(xcm.into()),
1208			ClearError => ClearError,
1209			SetHints { hints } => SetHints { hints },
1210			ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket },
1211			Trap(code) => Trap(code),
1212			SubscribeVersion { query_id, max_response_weight } =>
1213				SubscribeVersion { query_id, max_response_weight },
1214			UnsubscribeVersion => UnsubscribeVersion,
1215			BurnAsset(assets) => BurnAsset(assets),
1216			ExpectAsset(assets) => ExpectAsset(assets),
1217			ExpectOrigin(origin) => ExpectOrigin(origin),
1218			ExpectError(error) => ExpectError(error),
1219			ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
1220			QueryPallet { module_name, response_info } =>
1221				QueryPallet { module_name, response_info },
1222			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1223				ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1224			ReportTransactStatus(response_info) => ReportTransactStatus(response_info),
1225			ClearTransactStatus => ClearTransactStatus,
1226			UniversalOrigin(j) => UniversalOrigin(j),
1227			ExportMessage { network, destination, xcm } =>
1228				ExportMessage { network, destination, xcm },
1229			LockAsset { asset, unlocker } => LockAsset { asset, unlocker },
1230			UnlockAsset { asset, target } => UnlockAsset { asset, target },
1231			NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner },
1232			RequestUnlock { asset, locker } => RequestUnlock { asset, locker },
1233			SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw },
1234			SetTopic(topic) => SetTopic(topic),
1235			ClearTopic => ClearTopic,
1236			AliasOrigin(location) => AliasOrigin(location),
1237			UnpaidExecution { weight_limit, check_origin } =>
1238				UnpaidExecution { weight_limit, check_origin },
1239			PayFees { asset } => PayFees { asset },
1240			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
1241				InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm },
1242			ExecuteWithOrigin { descendant_origin, xcm } =>
1243				ExecuteWithOrigin { descendant_origin, xcm: xcm.into() },
1244		}
1245	}
1246}
1247
1248impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
1250	fn weight(&self) -> Weight {
1251		use Instruction::*;
1252		match self {
1253			WithdrawAsset(assets) => W::withdraw_asset(assets),
1254			ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets),
1255			ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets),
1256			QueryResponse { query_id, response, max_weight, querier } =>
1257				W::query_response(query_id, response, max_weight, querier),
1258			TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary),
1259			TransferReserveAsset { assets, dest, xcm } =>
1260				W::transfer_reserve_asset(&assets, dest, xcm),
1261			Transact { origin_kind, fallback_max_weight, call } =>
1262				W::transact(origin_kind, fallback_max_weight, call),
1263			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1264				W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity),
1265			HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient),
1266			HrmpChannelClosing { initiator, sender, recipient } =>
1267				W::hrmp_channel_closing(initiator, sender, recipient),
1268			ClearOrigin => W::clear_origin(),
1269			DescendOrigin(who) => W::descend_origin(who),
1270			ReportError(response_info) => W::report_error(&response_info),
1271			DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary),
1272			DepositReserveAsset { assets, dest, xcm } =>
1273				W::deposit_reserve_asset(assets, dest, xcm),
1274			ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal),
1275			InitiateReserveWithdraw { assets, reserve, xcm } =>
1276				W::initiate_reserve_withdraw(assets, reserve, xcm),
1277			InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm),
1278			ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets),
1279			BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit),
1280			RefundSurplus => W::refund_surplus(),
1281			SetErrorHandler(xcm) => W::set_error_handler(xcm),
1282			SetAppendix(xcm) => W::set_appendix(xcm),
1283			ClearError => W::clear_error(),
1284			SetHints { hints } => W::set_hints(hints),
1285			ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket),
1286			Trap(code) => W::trap(code),
1287			SubscribeVersion { query_id, max_response_weight } =>
1288				W::subscribe_version(query_id, max_response_weight),
1289			UnsubscribeVersion => W::unsubscribe_version(),
1290			BurnAsset(assets) => W::burn_asset(assets),
1291			ExpectAsset(assets) => W::expect_asset(assets),
1292			ExpectOrigin(origin) => W::expect_origin(origin),
1293			ExpectError(error) => W::expect_error(error),
1294			ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
1295			QueryPallet { module_name, response_info } =>
1296				W::query_pallet(module_name, response_info),
1297			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1298				W::expect_pallet(index, name, module_name, crate_major, min_crate_minor),
1299			ReportTransactStatus(response_info) => W::report_transact_status(response_info),
1300			ClearTransactStatus => W::clear_transact_status(),
1301			UniversalOrigin(j) => W::universal_origin(j),
1302			ExportMessage { network, destination, xcm } =>
1303				W::export_message(network, destination, xcm),
1304			LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker),
1305			UnlockAsset { asset, target } => W::unlock_asset(asset, target),
1306			NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner),
1307			RequestUnlock { asset, locker } => W::request_unlock(asset, locker),
1308			SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw),
1309			SetTopic(topic) => W::set_topic(topic),
1310			ClearTopic => W::clear_topic(),
1311			AliasOrigin(location) => W::alias_origin(location),
1312			UnpaidExecution { weight_limit, check_origin } =>
1313				W::unpaid_execution(weight_limit, check_origin),
1314			PayFees { asset } => W::pay_fees(asset),
1315			InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } =>
1316				W::initiate_transfer(destination, remote_fees, preserve_origin, assets, remote_xcm),
1317			ExecuteWithOrigin { descendant_origin, xcm } =>
1318				W::execute_with_origin(descendant_origin, xcm),
1319		}
1320	}
1321}
1322
1323pub mod opaque {
1324	pub type Xcm = super::Xcm<()>;
1327
1328	pub type Instruction = super::Instruction<()>;
1331}
1332
1333impl<Call> TryFrom<OldXcm<Call>> for Xcm<Call> {
1335	type Error = ();
1336	fn try_from(old_xcm: OldXcm<Call>) -> result::Result<Self, Self::Error> {
1337		Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::<result::Result<_, _>>()?))
1338	}
1339}
1340
1341impl<Call> TryFrom<OldInstruction<Call>> for Instruction<Call> {
1343	type Error = ();
1344	fn try_from(old_instruction: OldInstruction<Call>) -> result::Result<Self, Self::Error> {
1345		use OldInstruction::*;
1346		Ok(match old_instruction {
1347			WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?),
1348			ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?),
1349			ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?),
1350			QueryResponse { query_id, response, max_weight, querier: Some(querier) } =>
1351				Self::QueryResponse {
1352					query_id,
1353					querier: querier.try_into()?,
1354					response: response.try_into()?,
1355					max_weight,
1356				},
1357			QueryResponse { query_id, response, max_weight, querier: None } =>
1358				Self::QueryResponse {
1359					query_id,
1360					querier: None,
1361					response: response.try_into()?,
1362					max_weight,
1363				},
1364			TransferAsset { assets, beneficiary } => Self::TransferAsset {
1365				assets: assets.try_into()?,
1366				beneficiary: beneficiary.try_into()?,
1367			},
1368			TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset {
1369				assets: assets.try_into()?,
1370				dest: dest.try_into()?,
1371				xcm: xcm.try_into()?,
1372			},
1373			HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
1374				Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
1375			HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient },
1376			HrmpChannelClosing { initiator, sender, recipient } =>
1377				Self::HrmpChannelClosing { initiator, sender, recipient },
1378			Transact { origin_kind, require_weight_at_most, call } => Self::Transact {
1379				origin_kind,
1380				call: call.into(),
1381				fallback_max_weight: Some(require_weight_at_most),
1382			},
1383			ReportError(response_info) => Self::ReportError(QueryResponseInfo {
1384				query_id: response_info.query_id,
1385				destination: response_info.destination.try_into().map_err(|_| ())?,
1386				max_weight: response_info.max_weight,
1387			}),
1388			DepositAsset { assets, beneficiary } => {
1389				let beneficiary = beneficiary.try_into()?;
1390				let assets = assets.try_into()?;
1391				Self::DepositAsset { assets, beneficiary }
1392			},
1393			DepositReserveAsset { assets, dest, xcm } => {
1394				let dest = dest.try_into()?;
1395				let xcm = xcm.try_into()?;
1396				let assets = assets.try_into()?;
1397				Self::DepositReserveAsset { assets, dest, xcm }
1398			},
1399			ExchangeAsset { give, want, maximal } => {
1400				let give = give.try_into()?;
1401				let want = want.try_into()?;
1402				Self::ExchangeAsset { give, want, maximal }
1403			},
1404			InitiateReserveWithdraw { assets, reserve, xcm } => {
1405				let assets = assets.try_into()?;
1406				let reserve = reserve.try_into()?;
1407				let xcm = xcm.try_into()?;
1408				Self::InitiateReserveWithdraw { assets, reserve, xcm }
1409			},
1410			InitiateTeleport { assets, dest, xcm } => {
1411				let assets = assets.try_into()?;
1412				let dest = dest.try_into()?;
1413				let xcm = xcm.try_into()?;
1414				Self::InitiateTeleport { assets, dest, xcm }
1415			},
1416			ReportHolding { response_info, assets } => {
1417				let response_info = QueryResponseInfo {
1418					destination: response_info.destination.try_into().map_err(|_| ())?,
1419					query_id: response_info.query_id,
1420					max_weight: response_info.max_weight,
1421				};
1422				Self::ReportHolding { response_info, assets: assets.try_into()? }
1423			},
1424			BuyExecution { fees, weight_limit } => {
1425				let fees = fees.try_into()?;
1426				let weight_limit = weight_limit.into();
1427				Self::BuyExecution { fees, weight_limit }
1428			},
1429			ClearOrigin => Self::ClearOrigin,
1430			DescendOrigin(who) => Self::DescendOrigin(who.try_into()?),
1431			RefundSurplus => Self::RefundSurplus,
1432			SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?),
1433			SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?),
1434			ClearError => Self::ClearError,
1435			ClaimAsset { assets, ticket } => {
1436				let assets = assets.try_into()?;
1437				let ticket = ticket.try_into()?;
1438				Self::ClaimAsset { assets, ticket }
1439			},
1440			Trap(code) => Self::Trap(code),
1441			SubscribeVersion { query_id, max_response_weight } =>
1442				Self::SubscribeVersion { query_id, max_response_weight },
1443			UnsubscribeVersion => Self::UnsubscribeVersion,
1444			BurnAsset(assets) => Self::BurnAsset(assets.try_into()?),
1445			ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?),
1446			ExpectOrigin(maybe_location) => Self::ExpectOrigin(
1447				maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?,
1448			),
1449			ExpectError(maybe_error) => Self::ExpectError(
1450				maybe_error
1451					.map(|(num, old_error)| (num, old_error.try_into()))
1452					.map(|(num, result)| result.map(|inner| (num, inner)))
1453					.transpose()
1454					.map_err(|_| ())?,
1455			),
1456			ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code),
1457			QueryPallet { module_name, response_info } => Self::QueryPallet {
1458				module_name,
1459				response_info: response_info.try_into().map_err(|_| ())?,
1460			},
1461			ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
1462				Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor },
1463			ReportTransactStatus(response_info) =>
1464				Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?),
1465			ClearTransactStatus => Self::ClearTransactStatus,
1466			UniversalOrigin(junction) =>
1467				Self::UniversalOrigin(junction.try_into().map_err(|_| ())?),
1468			ExportMessage { network, destination, xcm } => Self::ExportMessage {
1469				network: network.into(),
1470				destination: destination.try_into().map_err(|_| ())?,
1471				xcm: xcm.try_into().map_err(|_| ())?,
1472			},
1473			LockAsset { asset, unlocker } => Self::LockAsset {
1474				asset: asset.try_into().map_err(|_| ())?,
1475				unlocker: unlocker.try_into().map_err(|_| ())?,
1476			},
1477			UnlockAsset { asset, target } => Self::UnlockAsset {
1478				asset: asset.try_into().map_err(|_| ())?,
1479				target: target.try_into().map_err(|_| ())?,
1480			},
1481			NoteUnlockable { asset, owner } => Self::NoteUnlockable {
1482				asset: asset.try_into().map_err(|_| ())?,
1483				owner: owner.try_into().map_err(|_| ())?,
1484			},
1485			RequestUnlock { asset, locker } => Self::RequestUnlock {
1486				asset: asset.try_into().map_err(|_| ())?,
1487				locker: locker.try_into().map_err(|_| ())?,
1488			},
1489			SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw },
1490			SetTopic(topic) => Self::SetTopic(topic),
1491			ClearTopic => Self::ClearTopic,
1492			AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?),
1493			UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution {
1494				weight_limit,
1495				check_origin: check_origin
1496					.map(|location| location.try_into())
1497					.transpose()
1498					.map_err(|_| ())?,
1499			},
1500		})
1501	}
1502}
1503
1504#[cfg(test)]
1505mod tests {
1506	use super::{prelude::*, *};
1507	use crate::{
1508		v4::{
1509			AssetFilter as OldAssetFilter, Junctions::Here as OldHere, WildAsset as OldWildAsset,
1510		},
1511		MAX_INSTRUCTIONS_TO_DECODE,
1512	};
1513
1514	#[test]
1515	fn basic_roundtrip_works() {
1516		let xcm = Xcm::<()>(vec![TransferAsset {
1517			assets: (Here, 1u128).into(),
1518			beneficiary: Here.into(),
1519		}]);
1520		let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset {
1521			assets: (OldHere, 1u128).into(),
1522			beneficiary: OldHere.into(),
1523		}]);
1524		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1525		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1526		assert_eq!(new_xcm, xcm);
1527	}
1528
1529	#[test]
1530	fn teleport_roundtrip_works() {
1531		let xcm = Xcm::<()>(vec![
1532			ReceiveTeleportedAsset((Here, 1u128).into()),
1533			ClearOrigin,
1534			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1535		]);
1536		let old_xcm: OldXcm<()> = OldXcm::<()>(vec![
1537			OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()),
1538			OldInstruction::ClearOrigin,
1539			OldInstruction::DepositAsset {
1540				assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)),
1541				beneficiary: OldHere.into(),
1542			},
1543		]);
1544		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1545		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1546		assert_eq!(new_xcm, xcm);
1547	}
1548
1549	#[test]
1550	fn reserve_deposit_roundtrip_works() {
1551		let xcm = Xcm::<()>(vec![
1552			ReserveAssetDeposited((Here, 1u128).into()),
1553			ClearOrigin,
1554			BuyExecution {
1555				fees: (Here, 1u128).into(),
1556				weight_limit: Some(Weight::from_parts(1, 1)).into(),
1557			},
1558			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1559		]);
1560		let old_xcm = OldXcm::<()>(vec![
1561			OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()),
1562			OldInstruction::ClearOrigin,
1563			OldInstruction::BuyExecution {
1564				fees: (OldHere, 1u128).into(),
1565				weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)),
1566			},
1567			OldInstruction::DepositAsset {
1568				assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)),
1569				beneficiary: OldHere.into(),
1570			},
1571		]);
1572		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1573		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1574		assert_eq!(new_xcm, xcm);
1575	}
1576
1577	#[test]
1578	fn deposit_asset_roundtrip_works() {
1579		let xcm = Xcm::<()>(vec![
1580			WithdrawAsset((Here, 1u128).into()),
1581			DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
1582		]);
1583		let old_xcm = OldXcm::<()>(vec![
1584			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1585			OldInstruction::DepositAsset {
1586				assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)),
1587				beneficiary: OldHere.into(),
1588			},
1589		]);
1590		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1591		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1592		assert_eq!(new_xcm, xcm);
1593	}
1594
1595	#[test]
1596	fn deposit_reserve_asset_roundtrip_works() {
1597		let xcm = Xcm::<()>(vec![
1598			WithdrawAsset((Here, 1u128).into()),
1599			DepositReserveAsset {
1600				assets: Wild(AllCounted(1)),
1601				dest: Here.into(),
1602				xcm: Xcm::<()>(vec![]),
1603			},
1604		]);
1605		let old_xcm = OldXcm::<()>(vec![
1606			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1607			OldInstruction::DepositReserveAsset {
1608				assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)),
1609				dest: OldHere.into(),
1610				xcm: OldXcm::<()>(vec![]),
1611			},
1612		]);
1613		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1614		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1615		assert_eq!(new_xcm, xcm);
1616	}
1617
1618	#[test]
1619	fn transact_roundtrip_works() {
1620		let xcm = Xcm::<()>(vec![
1622			WithdrawAsset((Here, 1u128).into()),
1623			Transact {
1624				origin_kind: OriginKind::SovereignAccount,
1625				call: vec![200, 200, 200].into(),
1626				fallback_max_weight: Some(Weight::from_parts(1_000_000, 1_024)),
1627			},
1628		]);
1629		let old_xcm = OldXcm::<()>(vec![
1630			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1631			OldInstruction::Transact {
1632				origin_kind: OriginKind::SovereignAccount,
1633				call: vec![200, 200, 200].into(),
1634				require_weight_at_most: Weight::from_parts(1_000_000, 1_024),
1635			},
1636		]);
1637		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap());
1638		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1639		assert_eq!(new_xcm, xcm);
1640
1641		let xcm_without_fallback = Xcm::<()>(vec![
1643			WithdrawAsset((Here, 1u128).into()),
1644			Transact {
1645				origin_kind: OriginKind::SovereignAccount,
1646				call: vec![200, 200, 200].into(),
1647				fallback_max_weight: None,
1648			},
1649		]);
1650		let old_xcm = OldXcm::<()>(vec![
1651			OldInstruction::WithdrawAsset((OldHere, 1u128).into()),
1652			OldInstruction::Transact {
1653				origin_kind: OriginKind::SovereignAccount,
1654				call: vec![200, 200, 200].into(),
1655				require_weight_at_most: Weight::MAX,
1656			},
1657		]);
1658		assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm_without_fallback.clone()).unwrap());
1659		let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
1660		let xcm_with_max_weight_fallback = Xcm::<()>(vec![
1661			WithdrawAsset((Here, 1u128).into()),
1662			Transact {
1663				origin_kind: OriginKind::SovereignAccount,
1664				call: vec![200, 200, 200].into(),
1665				fallback_max_weight: Some(Weight::MAX),
1666			},
1667		]);
1668		assert_eq!(new_xcm, xcm_with_max_weight_fallback);
1669	}
1670
1671	#[test]
1672	fn decoding_respects_limit() {
1673		let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]);
1674		let encoded = max_xcm.encode();
1675		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok());
1676
1677		let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]);
1678		let encoded = big_xcm.encode();
1679		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1680
1681		let nested_xcm = Xcm::<()>(vec![
1682			DepositReserveAsset {
1683				assets: All.into(),
1684				dest: Here.into(),
1685				xcm: max_xcm,
1686			};
1687			(MAX_INSTRUCTIONS_TO_DECODE / 2) as usize
1688		]);
1689		let encoded = nested_xcm.encode();
1690		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1691
1692		let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]);
1693		let encoded = even_more_nested_xcm.encode();
1694		assert_eq!(encoded.len(), 342530);
1695		assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition");
1697		assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err());
1698	}
1699}